我正在跟着一本书来尝试创建一个Flask博客。我是Flask的新手。我更新了一个模型,所以代码看起来像这样:
class Entry(db.Model):
STATUS_PUBLIC = 0
STATUS_DRAFT = 1
STATUS_DELETED = 2
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100))
slug = db.Column(db.String(100), unique=True)
body = db.Column(db.Text)
status = db.Column(db.SmallInteger, default=STATUS_PUBLIC)
created_timestamp = db.Column(db.DateTime, default=datetime.datetime.now)
modified_timestamp = db.Column(
db.DateTime,
default=datetime.datetime.now,
onupdate=datetime.datetime.now)
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
添加最后一行author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
导致数据库升级失败,并显示错误:
File "manage.py", line 5, in <module>
manager.run()
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/flask_script/__init__.py", line 412, in run
result = self.handle(sys.argv[0], sys.argv[1:])
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/flask_script/__init__.py", line 383, in handle
res = handle(*args, **config)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/flask_script/commands.py", line 216, in __call__
return self.run(*args, **kwargs)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/flask_migrate/__init__.py", line 259, in upgrade
command.upgrade(config, revision, sql=sql, tag=tag)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/command.py", line 254, in upgrade
script.run_env()
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/script/base.py", line 425, in run_env
util.load_python_file(self.dir, 'env.py')
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/util/pyfiles.py", line 93, in load_python_file
module = load_module_py(module_id, path)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/util/compat.py", line 75, in load_module_py
mod = imp.load_source(module_id, path, fp)
File "migrations/env.py", line 87, in <module>
run_migrations_online()
File "migrations/env.py", line 80, in run_migrations_online
context.run_migrations()
File "<string>", line 8, in run_migrations
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/runtime/environment.py", line 836, in run_migrations
self.get_context().run_migrations(**kw)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/runtime/migration.py", line 330, in run_migrations
step.migration_fn(**kw)
File "/home/devblog/projects/blog/app/migrations/versions/6b49bdaf06ce_.py", line 22, in upgrade
batch_op.create_foreign_key(None, 'user', ['author_id'], ['id'])
File "/usr/lib64/python2.7/contextlib.py", line 24, in __exit__
self.gen.next()
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/operations/base.py", line 299, in batch_alter_table
impl.flush()
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/operations/batch.py", line 80, in flush
fn(*arg, **kw)
File "/home/devblog/projects/blog/venv/lib/python2.7/site-packages/alembic/operations/batch.py", line 337, in add_constraint
raise ValueError("Constraint must have a name")
ValueError: Constraint must have a name
问题似乎在于迁移脚本的升级功能:
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('entry', schema=None) as batch_op:
#batch_op.create_foreign_key(None, 'user', ['author_id'], ['id'])
batch_op.create_foreign_key("author_id", 'user', ['author_id'], ['id'])
我通过评论原始行,删除None
并使用'author_id'
来“修复”此内容。
我使用此处的文档http://alembic.zzzcomputing.com/en/latest/ops.html来提供修复程序。相关部分:
create_foreign_key(constraint_name,source_table,referent_table, local_cols,remote_cols,onupdate = None,ondelete = None, deferrable = None,initial = None,match = None,source_schema = None, referent_schema = None,** dialect_kw)
这在内部生成一个包含必要的Table对象 列,然后生成一个新的ForeignKeyConstraint对象 然后与表联系。与之关联的任何事件侦听器 这个动作将正常发射。 AddConstraint构造是 最终用于生成ALTER语句。
参数:name - 外键约束的名称。名字是 必要的,以便可以发出ALTER语句。对于那些设置 使用自动命名方案,如配置中所述 约束命名约定,此处的名称可以是None,作为事件 侦听器将该名称应用于约束对象 与表相关联。 source_table - 源的字符串名称 表。 referent_table - 目标表的字符串名称。 local_cols - 源表中的字符串列名称列表。 remote_cols - 远程表中的字符串列名列表。 onupdate - 可选字符串。如果设置,则在发出ON UPDATE时 为此约束发出DDL。典型值包括CASCADE, 删除和限制。 ondelete - 可选字符串。如果设置,则发出ON 为此约束发出DDL时删除。典型值 包括CASCADE,DELETE和RESTRICT。可延迟的 - 可选的布尔。如果 设置,在为此发出DDL时发出DEFERRABLE或NOT DEFERRABLE 约束。 source_schema - 源表的可选模式名称。 referent_schema¶ - 目标表的可选模式名称。
我认为我添加了一个约束名称,而不是None
,它已经“修复”了这个问题。这是对的吗?
此外,看起来该函数需要5个参数才能工作。它如何只用4?
感谢任何建议。
答案 0 :(得分:4)
Mark Steward's solution对我来说非常适合添加简单的外键列。
无论您在何处声明/定义&#34; db&#34;,请执行以下操作 -
from sqlalchemy import MetaData
naming_convention = {
"ix": 'ix_%(column_0_label)s',
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_%(column_0_name)s",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s"
}
db = SQLAlchemy(metadata=MetaData(naming_convention=naming_convention))
然后,在初始化迁移应用程序(flask-migrate)的地方,传递render_as_batch=True
-
migrate.init_app(app, db, render_as_batch=True)