使用Flask-SQLAlchemy和Blueprints循环导入db引用

S18*_*182 33 flask flask-sqlalchemy

我正在使用Flask-SQLAlchemy和Blueprints,我无法使用循环导入.我知道我可以在函数内部编写导入并使其工作但它听起来很讨厌,我想与社区确认是否有更好的方法来做到这一点.

问题是我有一个模块(blueprints.py),我在其中声明数据库并导入蓝图,但这些蓝图需要同时导入数据库声明.

这是代码(重要部分的摘录):

application.apps.people.views.py

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()
Run Code Online (Sandbox Code Playgroud)

application.blueprints.py

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')
Run Code Online (Sandbox Code Playgroud)

我已经阅读了文档和我在这个主题上发现的问题,但我仍然找不到我要找的答案.我已经找到了这一章(https://pythonhosted.org/Flask-SQLAlchemy/contexts.html),它建议将初始化代码放在方法中,但循环导入仍然存在.

编辑 我使用模式Application Factory修复了问题

S18*_*182 48

我在Application Factory模式的帮助下解决了这个问题.我在第三个模块中声明数据库,稍后在我启动应用程序的同一模块中对其进行配置.

这导致以下导入:

  • database.py→app.py
  • views.py→app.py
  • database.py→views.py

没有循环导入.在调用数据库操作之前,确保启动并配置应用程序非常重要.

这是一个示例应用程序:

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()
Run Code Online (Sandbox Code Playgroud)

database.py

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 你能提供一个使用这种方法的 github 存储库吗? (2认同)

dex*_*ity 24

Flask的圆形进口让我疯狂.来自文档:http://flask.pocoo.org/docs/0.10/patterns/packages/

...请注意,这一般是个坏主意,但实际上这很好.

这不好.这是非常错误的.我也考虑将任何代码__init__.py作为一种不好的做法.它使应用程序难以扩展.蓝图是一种缓解循环导入问题的方法.我认为Flask需要更多这方面的东西.

  • 太刺激了! (2认同)
  • 将核心应用程序代码放在 app/__init__.py 文件中似乎很常见:https://www.digitalocean.com/community/tutorials/how-to-struct-large-flask-applications https://github。 com/mitsuhiko/flask/wiki/Large-app-how-to 甚至在 O'Reily Flask Web 应用程序书中 (2认同)
  • 您能否提供一些关于蓝图如何帮助避免循环的指示? (2认同)

Sam*_*Sam 5

我知道这个问题已经解决了,但是我以一种略有不同的方式解决了这个问题,并想回答一下,以防其他人受到帮助。

最初,我的应用程序代码(例如my_app.py)具有以下行:

db = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)

因此在我中models.py,我有:

from my_app import db

class MyModel(db.Model):
    # etc
Run Code Online (Sandbox Code Playgroud)

因此在MyModelin中使用时的循环引用my_app。我对此进行了更新,以便models.py具有以下内容:

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
Run Code Online (Sandbox Code Playgroud)

然后在my_app

from models import db, MyModel  # importing db is new

# ...

db.init_app(app)  # call init_app here rather than initialising db here
Run Code Online (Sandbox Code Playgroud)

  • 如果有多个模型文件会发生什么?他们都必须“from models import db”吗? (2认同)
  • @PaymahnMoghadasian 我在`models.py` 中有多个模型类。如果你有多个包含模型的文件,那会更复杂 - 你需要将 `db = SQLAlchemy()` 移动到一个单独的文件,我认为模型和应用程序都从中导入(但请注意我我没试过这个)。 (2认同)
  • 这适用于您在答案中描述的简单情况,但如果您要在单独的文件中定义多个模型,则会出现很大的问题。 (2认同)