Raf*_*ges 13 python flask flask-sqlalchemy
我很难让我的应用程序运行.每当我尝试在包中分离模块时,Flask-SQLAlchemy扩展会创建一个空数据库.为了更好地解释我在做什么,让我展示我的项目是如何构建的:
Project
|
|-- Model
| |-- __init__.py
| |-- User.py
|
|-- Server
| |-- __init__.py
|
|-- API
| |-- __init__.py
Run Code Online (Sandbox Code Playgroud)
这个想法很简单:我想为我的模型创建一个包,因为我不喜欢在单个包中传播代码,并且单独的"子"项目(如API),因为将来我会更好地使用蓝图隔离子应用程序.
代码很简单:
一,Model.__init__.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Run Code Online (Sandbox Code Playgroud)
请注意,我创建它只是为了使用SQLAlchemy()整个包中的单个对象.不,我们去Model.User
from Model import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
Name = db.Column(db.String(80))
Age = db.Column(db.Integer)
...
Run Code Online (Sandbox Code Playgroud)
再次注意我用过的模型导入数据库允许相同的数据库对象.
最后,Server.__init__.py这样做:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import Model, API
db = Model.db
def main():
app = Flask("__main__")
db = SQLAlchemy(app)
db.create_all()
API.SetAPIHookers(app)
app.run(host="0.0.0.0", port=5000, debug=True)
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
从我的角度来看,db = SQLAlchemy(app)允许我传递我的app对象而不创建循环引用.
问题是每当我运行此代码时,sqlite数据库文件都是空的.这让我觉得Python可能不会像我想象的那样导入东西.因此,我通过删除导入模型并直接在服务器内创建用户来测试我的理论......并且瞧,它有效!
现在我的问题是:是否有一种"pythonic"方式可以正确地分离我想要的模块,还是应该将所有内容放在同一个包中?
Mar*_*eth 22
现在,您已经使用与" 应用程序工厂 "模式(由Flask文档调用)相当的粗略设置应用程序.这是一个Flask的想法,而不是Python的想法.它有一些优点,但它也意味着你需要做一些事情,比如使用init_app方法而不是SQLAlchemy构造函数初始化SQLAlchemy对象.这样做没有"错误",但这意味着你需要create_all()在应用程序上下文中运行方法,如果你试图在main()方法中运行它,那么目前你不会这样.
有几种方法可以解决这个问题,但是由你决定你想要哪一种(没有正确的答案):
这样,您就不会在函数中创建应用程序.相反,你把它放在某个地方(比如project/__init__.py).你的project/__init__.py文件可以导入models包,而models包可以导入app从project.这是一个循环引用,但只要在尝试导入之前首先在包中app创建对象,这是可以的.有关可以将包拆分为多个包的示例,请参阅有关较大应用程序模式的Flask文档,但仍然可以通过使用循环引用使这些其他包能够使用该对象.文档甚至说:projectmodelapppackageapp
每个Python程序员都讨厌它们,但我们只添加了一些:循环导入.[...]请注意,这一般是一个坏主意,但实际上这很好.
如果执行此操作,则可以更改Models/__init__.py文件以SQLAlchemy使用构造函数中的应用程序引用来构建对象.这样,您就可以使用对象的方法create_all()和drop_all()方法SQLAlchemy,如Flask-SQLAlchemy文档中所述.
如果继续使用现有的(在函数中创建应用程序),则需要SQLAlchemy在Models包中构建对象,而不将app对象作为构造函数的一部分使用(如您所做).在您的主要方法中,更改...
db = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)
......到......
db.init_app(app)
Run Code Online (Sandbox Code Playgroud)
然后,您需要将create_all()方法移动到应用程序上下文中的函数中.在项目早期为此做一些常见的方法是利用before_first_request()装饰器....
app = Flask(...)
@app.before_first_request
def initialize_database():
db.create_all()
Run Code Online (Sandbox Code Playgroud)
在"Flask"处理第一个请求之前运行"initialize_database"方法.您也可以使用以下app_context()方法在任何时候执行此操作:
app = Flask(...)
with app.app_context():
# This should work because we are in an app context.
db.create_all()
Run Code Online (Sandbox Code Playgroud)
要意识到如果您要继续使用Application Factory模式,您应该真正了解应用程序上下文的工作原理; 它起初可能会令人困惑,但必须意识到"应用程序未在db实例上注册而没有应用程序绑定到当前上下文"这样的错误.
你的问题是这一行:
db = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)
它应该是这样的:
db.init_app(app)
Run Code Online (Sandbox Code Playgroud)
通过再次运行SQLAlchemy应用程序,您将db重新分配给新创建的db obj.
请尽量不要离开应用程序工厂设置.它消除了导入时间的副作用,是一件好事.实际上,您可能希望在工厂内部导入db,因为导入Base的子类(在本例中为db.model)具有自己的副作用(这不是问题).
初始化您的应用程序__init__.py意味着当您从程序包导入任何内容以供使用时,即使您不需要它,您也将最终引导您的应用程序.
| 归档时间: |
|
| 查看次数: |
9740 次 |
| 最近记录: |