1

I am creating my first larger Python Flask app and one of the modules I will be using is Flask_User. To make all a bit more manageable I wanted to impost a blueprint and factory app.

The structure is simple:

app.py
config.py
  auth/
    __init__.py
    models.py

So the goal is to have all authentication stuff in auth section. However, it comes down to where to initialize UserManager not to have errors, circular references, etc.

user_manager = UserManager(app, db, User)

How code looks like - app.py

from flask import Flask

# Configuration
from config import Config, HomeDevelopmentConfig

# Extensions
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

# INITIATE DB
db = SQLAlchemy()
migrate = Migrate() # this will run SQLAlchemy as well

from flask_user import UserManager
from auth.models import User
user_manager = UserManager()

# APPLICATION FACTORY
def create_app(config_class=Config):
    # Create app object
    app = Flask(__name__)
    
    # Load configuration
    app.config.from_object(config_class)

    # Register extensions
    db.init_app(app)
    migrate.init_app(app, db)

    user_manager = UserManager(app, db, User) # !!! this will not work - circular reference to User as User needs db

    # Close session with DB at the app shut down
    @app.teardown_request
    def shutdown_session(exception=None):
        db.session.remove()

    with app.app_context():
        # Register blueprints
        # Main flask app
        from main import bp_main
        app.register_blueprint(bp_main)
        
        # Authentication (flask-user)
        from auth import bp_auth
        app.register_blueprint(bp_auth)

        return app

# RUN APPLICATION
if __name__ == '__main__':
    app = create_app(HomeDevelopmentConfig)
    app.run()

models.py (should contain data structure for authentication)

from app import db
from flask_user import UserMixin #, UserManager

class User(db.Model, UserMixin):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), nullable=False, unique=True)
    password = db.Column(db.String(255), nullable=False, server_default='')
    first_name = db.Column(db.String(100), nullable=False, server_default='')
    last_name = db.Column(db.String(100), nullable=False, server_default='')
    email_confirmed_at = db.Column(db.DateTime())
    active = db.Column('is_active', db.Boolean(), nullable=False, server_default='0')

    # Define the relationship to Role via UserRoles
    roles = db.relationship('Role', secondary='user_roles')

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(50), unique=True)

class UserRoles(db.Model, UserMixin):
    __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'))

and finally init.py for authentication:

from flask import blueprints

bp_auth = blueprints.Blueprint('auth', __name__)

from auth import models

Looks like mission impossible, but maybe you have some good hints. What works is to put all the code into app.py, but that make

Hikari_PL
  • 21
  • 2

0 Answers0