Je veux structurer mon Flask app quelque chose comme:
./site.py
./apps/members/__init__.py
./apps/members/models.py
apps.members
est un Flask Blueprint.
Maintenant, afin de créer les classes de modèle, j'ai besoin de disposer de l'application, par exemple:
# apps.members.models
from flask import current_app
from flaskext.sqlalchemy import SQLAlchemy
db = SQLAlchemy(current_app)
class Member(db.Model):
# fields here
pass
Mais si j'essaie d'importer ce modèle dans mon application Blueprint, j'obtiens le redouté RuntimeError: working outside of request context
. Comment puis-je récupérer correctement mon application ici? Les importations relatives peuvent fonctionner, mais elles sont plutôt laides et ont leurs propres problèmes de contexte, par exemple:
from ...site import app
# ValueError: Attempted relative import beyond toplevel package
Le module flask_sqlalchemy
Ne doit pas nécessairement être initialisé avec l'application: vous pouvez le faire à la place:
# apps.members.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Member(db.Model):
# fields here
pass
Ensuite, dans la configuration de votre application, vous pouvez appeler init_app
:
# apps.application.py
from flask import Flask
from apps.members.models import db
app = Flask(__name__)
# later on
db.init_app(app)
De cette façon, vous pouvez éviter les importations cycliques.
Ce motif ne nécessite pas la place de tous vos modèles dans un seul fichier. Importez simplement la variable db
dans chacun de vos modules de modèle.
# apps.shared.models
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
# apps.members.models
from apps.shared.models import db
class Member(db.Model):
# TODO: Implement this.
pass
# apps.reporting.members
from flask import render_template
from apps.members.models import Member
def report_on_members():
# TODO: Actually use arguments
members = Member.filter(1==1).all()
return render_template("report.html", members=members)
# apps.reporting.routes
from flask import Blueprint
from apps.reporting.members import report_on_members
reporting = Blueprint("reporting", __name__)
reporting.route("/member-report", methods=["GET","POST"])(report_on_members)
# apps.application
from flask import Flask
from apps.shared import db
from apps.reporting.routes import reporting
app = Flask(__name__)
db.init_app(app)
app.register_blueprint(reporting)
Note: ceci est un esquisse de la puissance que cela vous donne - il y a évidemment beaucoup plus que ce que vous pouvez faire pour rendre le développement encore plus facile (en utilisant un motif create_app
, en enregistrant automatiquement des plans dans certains dossiers, etc.)
un original app.py : http://pythonhosted.org/Flask-SQLAlchemy/quickstart.html#quickstart
...
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask.ext.sqlalchemy.SQLAlchemy(app)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
class Computer(db.Model):
id = db.Column(db.Integer, primary_key=True)
...
# Create the database tables.
db.create_all()
...
# start the flask loop
app.run()
Je viens de scinder une application.py en app.py et model.py sans utiliser Blueprint. Dans ce cas, la réponse ci-dessus ne fonctionne pas. Un code de ligne est nécessaire pour fonctionner.
avant :
db.init_app(app)
après :
db.app = app
db.init_app(app)
Et le lien suivant est très utile.
http://piotr.banaszkiewicz.org/blog/2012/06/29/flask-sqlalchemy-init_app/