Flask_SQLAlchemy、db.create_all() 在通过服务 class 导入时无法 "see" 我的表
Flask_SQLAlchemy, db.create_all() is unable to "see" my tables when imported though a service class
意图:将我的代码重构为 MVC(这只是 model/database 部分),并让服务器在第一个 运行 上创建带有 table 的数据库,如果数据库或者 tables 不存在。
这在使用包含该文件中定义的所有 classes 和函数的“平面”文件时有效,但是在将函数移出到服务 class 并将模型移到它们自己的文件夹中后,模型 classes,db.create_all()
函数似乎无法再正确检测到 table class。
示例结构,(最小可行问题):
server.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
def main():
# Intentionally moved into the main() function to prevent import loops
from services.users import UserService
users = UserService(db)
db.create_all()
app.run(debug=True)
if __name__ == '__main__':
main()
services\users.py
# Class used to access users data using a session
from models.users import Users
class UserService:
def __init__(self, db):
self.db = db
def get_all(self):
return self.db.session.query(Users).all()
def get(self, uid):
return self.db.session.query(Users).get(uid)
def add(self, json):
user = Users(email=json['email'], password=json['password'])
self.db.session.add(user)
self.db.session.commit()
return user
models\users.py
# The actual model
from server import db
class Users(db.Model):
_id = db.Column("id", db.Integer, primary_key=True)
email = db.Column(db.Text)
password = db.Column(db.Text)
结果:数据库已创建,但它只是一个空文件,里面没有 tables。
我还尝试将 db.create_all()
放在服务 class def __init__(self, db)
中(在这里抓紧稻草),既作为自我参考又作为参数参考。都没有用。
我确信这是我明显遗漏的东西,但我已经将我的项目归结为最低限度,但仍然看不出为什么它不起作用 - 所以我不得不问。如何让 db.create_all()
正确检测我的 table classes 并实际创建所需的 tables,同时使用此代码结构(或类似的东西,以防我是否误解了 MVC)?
问题是server.py
执行了两次
- 在
models/users.py
中导入时
- 当
server.py
被调用到 运行 应用时
每次执行都会生成一个新的 db
实例。模型文件导入的 db
将模型添加到其 metadata
,应用程序 运行 时创建的 db
元数据为空。
您可以通过在 models/users.py
末尾和 main
函数中调用 db.create_all()
之前打印 id(db)
和 db.metadata.tables
来确认这一点.
您需要构建代码以便只创建一个 db
。例如,您可以将应用程序配置和创建代码移动到它自己的模块中,mkapp.py
(随意想出一个更好的名称):
mkapp.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
并在 server.py
中执行
from mkapp import app, db
并在 models/users.py
中执行
from mkapp import db
作为奖励,这还应该删除导入周期。
我用 Flask 不多,所以这个解决方案可能可以改进。例如,让一个函数创建 app
和 db
并记住结果可能比在顶级模块代码中创建它们更好。
意图:将我的代码重构为 MVC(这只是 model/database 部分),并让服务器在第一个 运行 上创建带有 table 的数据库,如果数据库或者 tables 不存在。
这在使用包含该文件中定义的所有 classes 和函数的“平面”文件时有效,但是在将函数移出到服务 class 并将模型移到它们自己的文件夹中后,模型 classes,db.create_all()
函数似乎无法再正确检测到 table class。
示例结构,(最小可行问题):
server.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
def main():
# Intentionally moved into the main() function to prevent import loops
from services.users import UserService
users = UserService(db)
db.create_all()
app.run(debug=True)
if __name__ == '__main__':
main()
services\users.py
# Class used to access users data using a session
from models.users import Users
class UserService:
def __init__(self, db):
self.db = db
def get_all(self):
return self.db.session.query(Users).all()
def get(self, uid):
return self.db.session.query(Users).get(uid)
def add(self, json):
user = Users(email=json['email'], password=json['password'])
self.db.session.add(user)
self.db.session.commit()
return user
models\users.py
# The actual model
from server import db
class Users(db.Model):
_id = db.Column("id", db.Integer, primary_key=True)
email = db.Column(db.Text)
password = db.Column(db.Text)
结果:数据库已创建,但它只是一个空文件,里面没有 tables。
我还尝试将 db.create_all()
放在服务 class def __init__(self, db)
中(在这里抓紧稻草),既作为自我参考又作为参数参考。都没有用。
我确信这是我明显遗漏的东西,但我已经将我的项目归结为最低限度,但仍然看不出为什么它不起作用 - 所以我不得不问。如何让 db.create_all()
正确检测我的 table classes 并实际创建所需的 tables,同时使用此代码结构(或类似的东西,以防我是否误解了 MVC)?
问题是server.py
执行了两次
- 在
models/users.py
中导入时
- 当
server.py
被调用到 运行 应用时
每次执行都会生成一个新的 db
实例。模型文件导入的 db
将模型添加到其 metadata
,应用程序 运行 时创建的 db
元数据为空。
您可以通过在 models/users.py
末尾和 main
函数中调用 db.create_all()
之前打印 id(db)
和 db.metadata.tables
来确认这一点.
您需要构建代码以便只创建一个 db
。例如,您可以将应用程序配置和创建代码移动到它自己的模块中,mkapp.py
(随意想出一个更好的名称):
mkapp.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.sqlite'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
并在 server.py
中执行
from mkapp import app, db
并在 models/users.py
中执行
from mkapp import db
作为奖励,这还应该删除导入周期。
我用 Flask 不多,所以这个解决方案可能可以改进。例如,让一个函数创建 app
和 db
并记住结果可能比在顶级模块代码中创建它们更好。