pythonflaskmodel-view-controllercircular-dependency

Flask MVC with Circular Dependency (dependency injection?)


I'm trying to create models to form the mvc in flask but it's marked as a circular dependency (db in init), I even removed the models to test and put them in for the controllers to use the bank, but the result was the same, what could I do to create the model of the user in user and use the db defined in app > __init__.py without circular dependency.

enter image description here

__init__.py

import os
from flask import Flask
from flask_pymongo import PyMongo
from app.routes.site import site
from app.routes.admin import admin

app = Flask(__name__)

app.config["MONGO_URI"] = (f'mongodb://'
                           f'{os.environ["MONGO_USERNAME"]}'
                           f':{os.environ["MONGO_PASSWORD"]}'
                           f'@{os.environ["MONGO_HOSTNAME"]}:27017'
                           f'/{os.environ["MONGO_DATABASE"]}?authSource=admin')
mongodb_client = PyMongo(app)
db = mongodb_client.db

app.secret_key = os.urandom(32).hex()

app.template_folder = 'views'

app.register_blueprint(site)

app.register_blueprint(admin)

app.static_folder = 'static'

app > controllers > AdminController.py

from flask import render_template, redirect, url_for, request, session
from app import db

def get():

    user_count = db.users.count_documents({})

    if user_count == 0:
        return redirect(url_for('admin/config'))

    return render_template('admin/index.html')

def post():
    email = request.form['email']
    password = request.form['password']

    user = db.users.find_one({'email': email, 'password': password})

    if user:
        session['user_id'] = str(user['_id'])
        return redirect(url_for('admin_page'))

    return render_template('admin/index.html', error='Credenciais inválidas')

app > routes > admin.py

from flask import Blueprint
from app.controllers.admin import (AdminController, AdminPageController,
                                   ConfigAdminController,
                                   RegisterUserAdminController)

admin = Blueprint('admin', __name__, url_prefix='/admin')

@admin.route('/', methods=['GET'])
def admin_index_get():
    return AdminController.get()

@admin.route('/', methods=['POST'])
def admin_index_post():
    return AdminController.post()

@admin.route('/admin_page', methods=['GET'])
def admin_page():
    return AdminPageController.get()

@admin.route('/config', methods=['GET'])
def admin_config():
    return ConfigAdminController.get()

@admin.route('/cadastrar_usuario', methods=['GET'])
def admin_register_user():
    return RegisterUserAdminController.get()

Solution

  • I managed to create an __init__ in the models that has PyMongo()

    models > __init__

    from flask_pymongo import PyMongo
    
    mongo = PyMongo()
    

    models > user

    from app.models import mongo
    
    class User:
        def __init__(self):
            self.mongo = mongo
            self.db = self.mongo.db
            self.collection = self.db.users
        
        def users_count(self):
            user_count = self.collection.count_documents({})
            return user_count
    
        def insert_user(self, email, password):
            result = self.collection.insert_one({"email": email, "password": password})
            
            if result.inserted_id:
                return str(result.inserted_id)
            else:
                return None
                
        def find_user_by_credentials(self, email, password):
            user = self.collection.find_one({"email": email, "password": password})
            if user:
                user['_id'] = str(user['_id'])
            return user
    

    controller > UserController

    from flask import render_template, redirect, url_for, request, session
    from app.models.user import User
    
    def get():
        user_instance = User()
        user_count = user_instance.users_count()
    
        if user_count == 0:
            return redirect(url_for('admin.admin_config_get'))
    
        return render_template('admin/index.html')
    
    def post():
        email = request.form['email']
        password = request.form['password']
    
        user_instance = User()
    
        # Chame o método find_user_by_credentials para verificar se o usuário existe
        existing_user = user_instance.find_user_by_credentials(email, password)
    
        if existing_user:
            session['user_id'] = existing_user['_id']
            return redirect(url_for('admin.admin_page'))
    
        return render_template('admin/index.html', error='Credenciais inválidas')
    

    __init__

    import os
    from flask import Flask
    from app.routes.site import site
    from app.routes.admin import admin
    from app.models import mongo
    from app.seeders import Seeder
    
    def create_app():
    
        app = Flask(__name__)
    
        app.secret_key = os.urandom(32).hex()
    
        app.template_folder = 'views'
    
        app.static_folder = 'static'
    
        app.config['UPLOAD_FOLDER'] = 'static/pdfs'
    
        app.register_blueprint(site)
    
        app.register_blueprint(admin)
    
        app.config["MONGO_URI"] = (f'mongodb://'
                               f'{os.environ["MONGO_USERNAME"]}'
                               f':{os.environ["MONGO_PASSWORD"]}'
                               f'@{os.environ["MONGO_HOSTNAME"]}:27017'
                               f'/{os.environ["MONGO_DATABASE"]}?authSource=admin')
    
        mongo.init_app(app)
    
        seeder = Seeder()
        
        seeder.seed_all_data()
        
        return app
    
    app = create_app()
    

    Now I'm going to work on improving security