我有两个用烧瓶和django写的存储库 这些项目共享数据库模型,该模型使用SQLAlchemy编写,并在Django ORM中编写 当我在flask中编写迁移脚本作为alembic时,django项目如何与该脚本一起迁移?
我也想到了SQLAlchemy的Django。但我无法使用SQLAlchemy找到Django项目。这是个坏主意吗? 感谢。
答案 0 :(得分:4)
在我们的工作场所,我们在同一个网站上同时使用django和flask。原因是django的管理员和模型系统编写代码非常快,它可以作为我们的后端(仅限员工)管理界面。另一方面,在烧瓶中编写前端要容易得多,因为每个页面都可以像一个python函数和Jinja2模板一样简单。 Flask表单需要一个额外的表单模型类(它易于编写),它指定表单中的所有字段,如果要将表单响应保存到SQL数据库,则需要第二个SQLAlchemy模型。如果你要在django中编写相同的表单,最简单的情况是你不编写表单模型,因为django框架隐式地从sql模型生成它。但是,在烧瓶中写“常规”页面仍然更快。
至于让两者一起玩得很好,它最终如何工作是我们首先编写django模型,因为数据库管理和sql架构迁移被烘焙到django中。然后我们使用SQLAlchemy的一个名为“reflection”的功能,它读取sql数据库并从模式生成sql模型。这样,当我们对django模型进行更改时,我们运行manage.py migrate(将模式更改部署到sql数据库),SQLAlchemy模型自动反映新模式,而无需我们触及Flask-SQLAlchemy模型。下面是一个示例,其中包含一些外键和一些时间戳,每当您使用ORM保存模型时,这些时间戳都会自动更新。我已经包含了这些,因为它们都是常见用例,并且都需要额外的代码。
Django模型:
from django.db import models
class DjangoModel(models.Model):
field1 = models.CharField(max_length=10)
field2 = models.IntegerField()
field3 = models.DateTimeField()
# We frequently use timestamps like this that the ORM updates automatically on creation and modification respectively.
created_timestamp = models.DateTimeField(auto_now_add=True)
modified_timestamp = models.DateTimeField(auto_now=True)
related = models.ForeignKey(SomeOtherDjangoModel, related_name='related_backref')
class Meta:
db_table = 'sql_table_name'
Flask-SQLAlchemy模型:
from flask import current_app
from flask_sqlalchemy import SQLAlchemy
import datetime
# The next three lines should be in your application.py ideally.
db = SQLAlchemy()
db.init_app(current_app)
db.Model.metadata.reflect(db.engine)
class FlaskSQLAlchemyModel(db.Model):
# All 6 fields from the django model and the implicit 'id' field django
# adds to its models will get reflected automatically the way this model
# is coded. The created_timestamp and modified_timestamp fields require
# special code for Flask-SQLAlchemy to update them automatically when
# you save a model instance. Relationships must be defined manually in
# Flask-SQLAlchemy, so there's code for that, too.
__table__ = db.Table('sql_table_name', db.Model.metadata,
# You'll need to "override" the timestamp fields to get flask-sqlalchemy to update them automatically on creation and modification respectively.
db.Column('created_timestamp', db.DateTime, default=datetime.datetime.now),
db.Column('modified_timestamp', db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now),
autoload=True,
extend_existing=True,
autoload_with=db.engine,
)
# You need to do model relationships manually in SQLAlchemy...
related = db.relationship(SomeOtherFlaskSQLAlchemyModel, backref=db.backref('related_backref', lazy='dynamic'))
以这种方式定义Flask-SQLAlchemy模型的警告是它们依赖于SQL数据库。在尝试导入模型所在的.py文件之前,需要正确配置Flask-SQLAlchemy及其db
对象,否则在导入时将获得一些令人讨厌的错误。如果将db
的定义放在与模型相同的文件中,它就会被初始化为:
from flask import current_app
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
db.init_app(current_app)
然后你需要像这样进行导入:
with app.app_context():
import module_with_flask_sqlalchemy_model
当然,app
需要加载Flask-SQLAlchemy的配置设置,否则无效。最好让模型文件执行from application import db
,并在设置from my_models import *
后让application.py执行db
。
正确配置后,Flask-SQLAlchemy模型将等同于这样定义的Flask-SQLAlchemy模型:
from flask import current_app
from flask_sqlalchemy import SQLAlchemy
import datetime
db = SQLAlchemy()
db.init_app(current_app)
class FlaskSQLAlchemyModel(db.Model):
__tablename__ = 'sql_table_name'
id = db.Column(db.Integer, primary_key=True)
field1 = db.Column(db.String(10))
field2 = db.Column(db.Integer)
field3 = db.Column(db.DateTime)
created_timestamp = db.Column(db.DateTime, default=datetime.datetime.now)
modified_timestamp = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
related_id = db.Column(db.Integer, db.ForeignKey('some_other_sql_table_name.id'))
related = db.relationship(SomeOtherFlaskSQLAlchemyModel, backref=db.backref('related_backref', lazy='dynamic'))
一旦你获得了django模型和反射的flask-sqlalchemy模型,那么你可以使用django的awesome migrate命令来创建具有正确模式的表。然后,flask-sqlalchemy模型将注意到它们已经被创建并自动填充。这样,您只需要担心django模型(减去时间戳字段和模型关系),然后让flask-sqlalchemy为您反映其余部分。
您需要做的最后一件事是将Flask-SQLAlchemy和Django配置为指向同一个SQL数据库。我猜你知道怎么做。我给你的一个提示是Flask和Django的settings.py可以是同一个文件而没有任何冲突。
答案 1 :(得分:2)
首先,不要这样做;你是为了一个充满痛苦的世界。使用API在应用程序之间传递数据。
但是如果你不愿意这样做,那么迁移实际上并没有任何问题。只在一个应用程序中写入所有这些,Django或Alembic并在那里运行它们。由于他们正在共享一个数据库表,所以这就是它。