Data-models¶
Note: The code examples below assume the use of Flask-SQLAlchemy
User data-model¶
In its simplest form, Flask-User makes use of a single data-model class called User:
# Define User data-model
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# User Authentication fields
email = db.Column(db.String(255), nullable=False, unique=True)
email_confirmed_at = db.Column(db.DateTime())
username = db.Column(db.String(50), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
# User fields
active = db.Column(db.Boolean()),
first_name = db.Column(db.String(50), nullable=False)
last_name = db.Column(db.String(50), nullable=False)
# Setup Flask-User
user_manager = UserManager(app, db, User)
The active
property is optional. Add it if your application needs
to disable users. Flask-User will not let users login if this field is set to False
.
Flexible class name¶
The User
class name can be anything you want:
class Client(db.Model, UserMixin):
...
user_manager = UserManager(app, db, Client)
Fixed data-model property names¶
The following data-model property names are fixed:
User.id
User.username # optional
User.password
User.email # optional
User.email_confirmed_at # optional
User.active # optional
User.roles # optional
User.user_emails # optional
Role.id # optional
Role.name # optional
The following property names are flexible:
UserRoles.id # optional
UserRoles.user_id # optional
UserRoles.role_id # optional
If you have existing code, and are unable to globally change the fixed property names, consider using helper getters and setters 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 database column names¶
SQLAlchemy allows developers to specify a database column name different from their corresponding data-model property name like so:
class User(db.Model, UserMixin):
...
# Map email property to email_address column
email = db.Column('email_address', db.String(255), nullable=False, unique=True)
Optional Role and UserRoles data-models¶
The optional Role
and UserRoles
data-models are only required for role-based authentication.
In this configuration, the User
data-model must aslo define a roles
relationship property.
The Role data-model holds the name of each role. This name will be matched to the @roles_required function decorator in a CASE SENSITIVE manner.
The UserRoles
data-model associates Users with their Roles.
# Define the User data-model
class User(db.Model, UserMixin):
...
# Relationships
roles = db.relationship('Role', secondary='user_roles')
# Define the Role data-model
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
# Define the UserRoles association table
class UserRoles(db.Model):
__tablename__ = 'user_roles'
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
Roles are defined by adding rows to the Role table with a specific Role.name value.
admin_role = Role(name='Admin')
db.session.commit()
Users are assigned one or more roles by adding them to the User.roles property:
# Create 'user007' user with 'secret' and 'agent' roles
user1 = User(
username='user007', email='admin@example.com', active=True,
password=user_manager.hash_password('Password1'))
user1.roles = [admin_role,]
db.session.commit()
Optional UserEmail data-model¶
Flask-User can be configured to allow for multiple emails per users, pointing to the same user account and sharing the same password. In this configuration, a separate UserEmail data-model class must be specified.
# Define User data-model
class User(db.Model, UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
# User Authentication fields
username = db.Column(db.String(50), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
# Relationship
user_emails = db.relationship('UserEmail')
# Define UserEmail data-model
class UserEmail(db.Model):
__tablename__ = 'user_emails'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
user = db.relationship('User', uselist=False)
# User email information
email = db.Column(db.String(255), nullable=False, unique=True)
email_confirmed_at = db.Column(db.DateTime())
is_primary = db.Column(db.Boolean(), nullable=False, server_default='0')
# Setup Flask-User
user_manager = UserManager(app, User, UserEmailClass=UserEmail)
The is_primary
property defines which email receives account notification emails.