自动生成迁移时如何使alembic或flask迁移名称外键?
我已经断断续续地解决这个问题相当长一段时间了,奇怪的是找不到一个简单的问题/答案组合。相关问题这里和此处。我终于找到了解决方案,所以我会提出并回答我自己的问题。
在 Flask SQLAlchemy(和常规 SQLAlchemy)中,您可以有一个像这样的列:
class Character(db.model):
background_id = db.Column(db.Integer, db.ForeignKey('backgrounds.id'))
当您运行 Flask db migrate 或 alembic revision --autogenerate 时,这将导致操作如下所示:
def upgrade():
op.create_foreign_key(None, 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(None, 'characters', type_='foreignkey')
这里的 None
很糟糕。事实上,如果您稍后尝试降级,这总是会失败,因为 drop_constraint
需要约束的名称。
您可以在每次生成迁移时更改此设置,如下所示:
def upgrade():
op.create_foreign_key('fk_characters_backgrounds', 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint('fk_characters_backgrounds', 'characters', type_='foreignkey')
哪个有效!
但如果您像我一样,您不想每次使用外键自动生成修订版时都必须记住执行此操作。
那么问题来了,我们怎样才能让它自动化呢?
I've been struggling with this issue on and off for quite some time, and strangely could not find a straightforward question/answer combo on this on SO. Related questions here and here. I finally found a solution so I will ask and answer my own question.
In Flask SQLAlchemy (and regular SQLAlchemy), you can have a column like this:
class Character(db.model):
background_id = db.Column(db.Integer, db.ForeignKey('backgrounds.id'))
When you run flask db migrate
, or alembic revision --autogenerate
, this will result in an operation that looks like this:
def upgrade():
op.create_foreign_key(None, 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint(None, 'characters', type_='foreignkey')
The None
here is bad. In fact, if you try to downgrade later, this will always fail, because drop_constraint
needs the name of the constraint.
You can change this every time you generate a migration, like this:
def upgrade():
op.create_foreign_key('fk_characters_backgrounds', 'characters', 'backgrounds', ['background_id'], ['id'])
def downgrade():
op.drop_constraint('fk_characters_backgrounds', 'characters', type_='foreignkey')
Which works!
But if you're like me, you don't want to have to remember to do this every time you autogenerate a revision with a foreign key.
So the question is, how can we make this automatic?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
建议的最佳实践中有这个问题的答案 此处,位于“命名约定的重要性”部分的末尾。解决方案是将
naming_convention
添加到您的sqlalchemy
元数据中,如下所示:更具体地说,使用
Flask-SQLAlchemy
,在初始化数据库时执行此操作:瞧!如果你运行
autogenerate
,你会得到这样的信息:感谢 Flask Migrate 的创建者 Miguel Grinberg(毫不奇怪),他链接到 Alembic 文档中的正确页面,最终让我解决了这个问题! 有人在 Flask Migrate GitHub 上的一个问题中询问过这个问题,Miguel 正确指出这是一个 Alembic 问题,而不是 Flask Migrate 问题。
There is an answer to this question in the best practices suggested here, at the end of the section on The Importance of Naming Conventions. The solution is to add a
naming_convention
to yoursqlalchemy
metadata, like this:More specifically, with
Flask-SQLAlchemy
, do this when initializing your db:And voila! If you run
autogenerate
, you'll get this:Thanks (unsurprisingly) to Miguel Grinberg, creator of Flask Migrate, for having linked to the correct page in the Alembic docs that finally allowed me to solve this problem! Someone had asked about this in an issue on Flask Migrate GitHub, and Miguel correctly pointed out that this was an Alembic issue, not a Flask Migrate issue.
从答案中链接的同一文档 Willow 中提取:此处。
如果您已为 SQLAlchemy 引擎定义了 DeclarativeBase 模型,并且您的声明如下所示:
不要在 SQLAlchemy 声明中定义元数据。
相反,在 DeclarativeBase 类中定义元数据,并使用元数据传递
model_class
:然后,当您运行
flask db migrate
时,将应用命名约定Pulling from the same document Willow linked in their answer: here.
If you have defined a DeclarativeBase model for your SQLAlchemy engine, and your declaration looks like this:
Don't define the metadata within your SQLAlchemy declaration.
Instead, define the metadata inside your DeclarativeBase class, and pass the
model_class
with the metadata:Then the naming conventions will apply when you run
flask db migrate