J'utilise Flask-SQLAlchemy et Blueprints et je ne peux pas m'empêcher d'utiliser des importations circulaires. Je sais que je peux écrire des importations à l'intérieur des fonctions et le faire fonctionner mais cela semble désagréable, je voudrais confirmer avec la communauté s'il existe une meilleure façon de le faire.
Le problème est que j'ai un module (blueprints.py) où je déclare la base de données et importe les plans mais ces plans doivent importer la déclaration de base de données en même temps.
Voici le code (extrait des parties importantes):
from application.blueprints import db
people = Blueprint('people', __name__,
template_folder='templates',
static_folder='static')
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
@people.route('/all')
def all():
users = User.query.all()
from application.apps.people.views import people
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
app.register_blueprint(people, url_prefix='/people')
J'ai lu la documentation et les questions que j'ai trouvées sur ce sujet, mais je ne trouve toujours pas la réponse que je cherche. J'ai trouvé ce chapitre ( https://pythonhosted.org/Flask-SQLAlchemy/contexts.html ) où il suggère de mettre le code d'initialisation dans une méthode mais l'importation circulaire persiste toujours.
Modifier J'ai résolu le problème en utilisant le modèle Application Factory
J'ai résolu le problème à l'aide du modèle Application Factory . Je déclare la base de données dans un troisième module et la configure plus tard dans le même module dans lequel je démarre l'application.
Il en résulte les importations suivantes:
Il n'y a pas d'importation circulaire. Il est important de s'assurer que l'application a été démarrée et configurée avant d'appeler des opérations de base de données.
Voici un exemple d'application:
app.py
from database import db
from flask import Flask
import os.path
from views import User
from views import people
def create_app():
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:////tmp/test.db"
db.init_app(app)
app.register_blueprint(people, url_prefix='')
return app
def setup_database(app):
with app.app_context():
db.create_all()
user = User()
user.username = "Tom"
db.session.add(user)
db.session.commit()
if __name__ == '__main__':
app = create_app()
# Because this is just a demonstration we set up the database like this.
if not os.path.isfile('/tmp/test.db'):
setup_database(app)
app.run()
database.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
views.py
from database import db
from flask.blueprints import Blueprint
people = Blueprint('people', __name__,
template_folder='templates',
static_folder='static')
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
@people.route('/')
def test():
user = User.query.filter_by(username="Tom").first()
return "Test: Username %s " % user.username
Les importations circulaires dans Flask me rendent fou. D'après les documents: http://flask.pocoo.org/docs/0.10/patterns/packages/
... Sachez que c'est une mauvaise idée en général mais ici, c'est très bien.
Ce n'est pas bien. C'est profondément faux. J'envisage également de mettre n'importe quel code dans __init__.py
comme une mauvaise pratique. Cela rend l'application plus difficile à mettre à l'échelle. Les plans directeurs sont un moyen d'atténuer le problème des importations circulaires. Je pense que Flask a besoin de plus de cela.
Je sais que cela a déjà été résolu, mais je l'ai résolu d'une manière légèrement différente et je voulais répondre au cas où cela aiderait les autres.
À l'origine, mon code d'application (par exemple my_app.py
) avait cette ligne:
db = SQLAlchemy(app)
Et donc dans mon models.py
, J'ai eu:
from my_app import db
class MyModel(db.Model):
# etc
d'où les références circulaires lors de l'utilisation de MyModel
dans my_app
. J'ai mis à jour ceci pour que models.py ait ceci:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() # note no "app" here, and no import from my_app above
class MyModel(db.Model):
# etc as before
puis dans my_app
:
from models import db, MyModel # importing db is new
# ...
db.init_app(app) # call init_app here rather than initialising db here
Serge, sortez la définition des modèles dans un fichier séparé appelé models.py
. Enregistrez le plan dans le fichier __init__.py
Du package.
Vous avez une importation circulaire car un fichier de plan tente d'importer la référence des personnes à partir de views.py
, Mais dans views.py
, Vous essayez d'importer la base de données à partir de blueprints.py
. Et tout cela se fait au niveau supérieur des modules.
Vous pouvez créer la structure de votre projet comme ceci:
app
__init__.py # registering of blueprints and db initialization
mods
__init__.py
people
__init__.py # definition of module (blueprint)
views.py # from .models import User
models.py # from app import db
PD:
Pour ceux qui sont dans le réservoir:
people/__init__.py
-> mod = Module('app.mods.people', 'people')
people/views.py
-> @mod.route('/page')
app/__init__.py
-> from app.mods import people; from app.mods.people import views; app.register_blueprint(people.mod, **options);