dow*_*123 10 django generic-foreign-key django-postgresql django-migrations django-generic-relations
我试图限制 GFK 只指向几个模型的对象,我认为 CheckConstraint 将是一个很好的方法,但是我得到了这个错误
class ManualAdjustment(Model):
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(null=True)
booking_obj = GenericForeignKey('content_type', 'object_id')
# should point to a app1.Booking1 or app2.Booking2 or app3.Booking3 only - trying to enforce this via CheckConstraint
class Meta:
constraints = [
models.CheckConstraint(
check=
Q(content_type__app_label='app1', content_type__model='booking1') |
Q(content_type__app_label='app2', content_type__model='booking2') |
Q(content_type__app_label='app3', content_type__model='booking3'),
name='myconstraint_only_certain_models'),
]
Run Code Online (Sandbox Code Playgroud)
execute_from_command_line(sys.argv)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/commands/sqlmigrate.py", line 30, in execute
return super().execute(*args, **options)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
output = self.handle(*args, **options)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/core/management/commands/sqlmigrate.py", line 64, in handle
sql_statements = executor.collect_sql(plan)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/migrations/executor.py", line 225, in collect_sql
state = migration.apply(state, schema_editor, collect_sql=True)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/migrations/migration.py", line 124, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/migrations/operations/models.py", line 827, in database_forwards
schema_editor.add_constraint(model, self.constraint)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 343, in add_constraint
sql = constraint.create_sql(model, self)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/constraints.py", line 47, in create_sql
check = self._get_check_sql(model, schema_editor)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/constraints.py", line 37, in _get_check_sql
where = query.build_where(self.check)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1296, in build_where
return self._add_q(q_object, used_aliases=set(), allow_joins=False, simple_col=True)[0]
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1312, in _add_q
current_negated, allow_joins, split_subq, simple_col)
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1318, in _add_q
split_subq=split_subq, simple_col=simple_col,
File "/Users/myuser/.virtualenvs/xenia371/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1199, in build_filter
raise FieldError("Joined field references are not permitted in this query")
django.core.exceptions.FieldError: Joined field references are not permitted in this query
Run Code Online (Sandbox Code Playgroud)
关于如何解决这个问题的任何线索?我以前使用过 GFK,但有了新的检查约束,它实际上现在可以成为一种很好的错误安全方式,如果我可以让它迁移
谢谢
使用该CheckConstraint功能无法实现这一点。Django 将所有 ORM 命令转换为低级 DB 特定命令,即使在 DB 级别也无法创建此类约束。事实上,我们只能应用CheckConstraint到单行添加/更新。
在该说明文件上PostgreSQL说:
除了要检查的新行或更新行之外,PostgreSQL 不支持引用表数据的 CHECK 约束。虽然违反此规则的 CHECK 约束在简单测试中可能看起来有效,但它不能保证数据库不会达到约束条件为假的状态(由于涉及的其他行的后续更改)。这将导致数据库转储和重新加载失败。即使完整的数据库状态与约束一致,重新加载也可能失败,因为行未按满足约束的顺序加载。如果可能,请使用 UNIQUE、EXCLUDE 或 FOREIGN KEY 约束来表达跨行和跨表限制。
如果您希望在行插入时对其他行进行一次性检查,而不是持续维护的一致性保证,则可以使用自定义触发器来实现这一点。(这种方法避免了转储/重新加载问题,因为 pg_dump 在重新加载数据之后才重新安装触发器,因此在转储/重新加载期间不会强制执行检查。)
因此,引入所需约束的唯一方法是使用 db 触发器。您可以创建空迁移并将数据库触发器添加到其中。
| 归档时间: |
|
| 查看次数: |
847 次 |
| 最近记录: |