Limitations

We want to be transparent about what this package can and can not do.

Python versions

Flask-User has been tested with Python 2.7, 3.4, 3.5, 3.6, 3.7 and 3.8.

Flask versions

Flask-User works with Flask 0.9+

Supported Databases

Flask-User makes use of DbAdapters to support different databases.

It ships with a SQLDbAdapter to support a wide range of SQL databases via Flask-SQLAlchemy (Firebird, Microsoft SQL Server, MySQL, Oracle, PostgreSQL, SQLite, Sybase and more).

It ships with a MongoDbAdapter to support MongoDB databases via Flask-MongoEngine.

Custom DbAdapters can be implemented to support other Databases.

Supported Email Mailers

Flask-User makes use of EmailAdapters to send email via several platforms.

It ships with a SMTPEmailAdapter a SendmailEmailAdapter and a SendGridEmailAdapter to send emails via SMTP, sendmail and SendGrid.

Custom EmailAdapters can be implemented to support other Email Mailers.

Fixed app.user_manager name

An initialized UserManager() instance will assign itself to the app.user_manager property. This app.user_manager name can not be changed.

Fixed data-model property names

The following data-model property names are fixed:

User.id
User.password
User.username                      # optional
User.email                         # optional
User.email_confirmed_at            # optional
User.active                        # optional
User.roles                         # optional
User.user_emails                   # optional
Role.name                          # optional
UserEmail.id                       # optional
UserEmail.email                    # optional
UserEmail.email_confirmed_at       # optional
UserInvitation.id                  # optional
UserInvitation.email               # optional
UserInvitation.invited_by_user_id  # optional

If you have existing code, and are unable to globally change a fixed property name, consider using Python’s getter and setter properties as a bridge:

class User(db.Model, UserMixin):
        ...
    # Existing code uses email_address instead of email
    email_address = db.Column(db.String(255), nullable=False, unique=True)
        ...

    # define email getter
    @property
    def email(self):
        return self.email_address   # on user.email: return user.email_address

    # define email setter
    @email.setter
    def email(self, value):
        self.email_address = value  # on user.email='xyz': set user.email_address='xyz'

Flexible data-model class, SQL table, and SQL column names

Data-model class names are unrestricted.
SQL table names are unrestricted.
SQL column names are unrestricted.

Here is an example of a data-model class with different class, table and column names:

# Use of the Member class name (instead of User)
class Member(db.Model, UserMixin):

    # Use of the 'members' SQL table (instead of 'users')
    __tablename__ = 'members'
        ...
    # Use of the 'email_address' SQL column (instead of 'email')
    email = db.Column('email_address', db.String(255), nullable=False, unique=True)

# Setup Flask-User
user_manager = UserManager(app, db, Member)    # Specify the Member class

Primary keys

Even though Flask-User relies on the following:

  • Primary key is a single property named id.
  • id properties are:
    • integers,
    • or strings,
    • or offer a string representation with str(id).

Developers can still support primary key properties named other than id:

class User(db.Model, UserMixin):
    # Composite primary key
    pk = db.Column(db.Integer, primary_key=True)
        ...
    # Map: id=user.id to: id=user.pk
    @property
    def id(self):
        return self.pk

    # Map: user.id=id to: user.pk=id
    @id.setter
    def id(self, value):
        self.pk = value

Developers can still support composite primary keys:

class User(db.Model, UserMixin):
    # Composite primary key
    pk1 = db.Column(db.Integer, primary_key=True)
    pk2 = db.Column(db.String, primary_key=True)
        ...
    # Map:  id=user.id  to:  id=str(pk1)+'|'+pk2
    @property
    def id(self):
        return str(self.pk1)+'|'+self.pk2    # Naive concatenation

    # Map:  user.id=str(pk1)+'|'+pk2  to:  user.pk1=pk1; user.pk2=pk2;
    @id.setter
    def id(self, value):
        items = value.split('|',1)    # Naive split
        self.pk1 = int(items[0])
        self.pk2 = items[1]

Developers can customize the TokenManager to accept IDs without string representations.