Rob*_*bin 12 database constraints foreign-keys django-models
我有一个Django项目,有多个django"应用程序".其中一个模型表示来自外部源的数据(我不控制这些数据).
我希望我的其他应用程序能够引用此"外部应用程序",但我想避免数据库完整性检查的所有模糊.我不希望db对这些"软外键"有任何限制.
你知道如何编写一个自定义字段来模拟真正的Django ForeignKey而不在数据库上创建硬约束吗?
也许这已经存在,但我在谷歌上没有运气.
在此先感谢您的帮助 :-)
注意:我知道带有content_types 的通用关系系统.但我不想要通用关系.我希望只有没有硬完整性约束的特定关系才能识别模型.
编辑:
我找到了相关的链接:
但我没有找到适合我的问题的答案.:(
编辑2012年6月4日:
我深入研究了django的代码以找到需要做的事情,但我认为简单地继承ForeignKey是不够的.你能告诉我一些如何做的指示吗?
注意:我使用South来管理我的数据库模式,所以我想我也需要对此做些什么.但它可能不在这里:)
如果您只想禁用对某个字段的 ForeignKey 约束检查,则只需添加db_constraint=False到该字段即可。
user = models.ForeignKey('User', db_constraint=False)
Run Code Online (Sandbox Code Playgroud)
另请参阅: Django - 如何防止创建数据库外键约束
借助 marianobianchi 的评论,ForeignKey.on_delete 的选项之一是
DO_NOTHING:不采取任何行动。如果您的数据库后端强制执行引用完整性,则这将导致 IntegrityError,除非您手动向数据库字段添加 SQL ON DELETE 约束(可能使用初始 sql)。
这与在数据库级别禁用外键约束相结合应该可以解决问题。据我所知,有两种方法可以做到这一点。您可以像这样完全禁用 fk 约束:
from django.db.backend.signals import connection_created
from django.dispatch import receiver
@receiver(connection_created)
def disable_constraints(sender, connection):
connection.disable_constraint_checking()
Run Code Online (Sandbox Code Playgroud)
看起来 django 数据库后端也提供了一个constraint_checks_disabled上下文管理器,因此您可以将相关的数据库访问包装在这样的代码中,以避免在整个过程中禁用检查:
from django.db import connection
with connection.constraint_checks_disabled():
do_stuff()
Run Code Online (Sandbox Code Playgroud)
各位,
我成功地做到了我想要的。
首先,我创建了一个新字段:
from django.db.models.deletion import DO_NOTHING
from django.db.models.fields.related import ForeignKey, ManyToOneRel
class SoftForeignKey(ForeignKey):
"""
This field behaves like a normal django ForeignKey only without hard database constraints.
"""
def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
ForeignKey.__init__(self, to, to_field=to_field, rel_class=rel_class, **kwargs)
self.on_delete = DO_NOTHING
no_db_constraints = True
Run Code Online (Sandbox Code Playgroud)
由于我使用 South 来管理我的数据库架构,因此我必须添加以下内容:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], [r'^ecm\.lib\.softfk\.SoftForeignKey'])
Run Code Online (Sandbox Code Playgroud)
然后,我必须向南进行猴子修补,以便将no_db_constraints参数考虑在内。FK 约束的创建涉及两个函数:
from django.db.models.deletion import DO_NOTHING
from django.db.models.fields.related import ForeignKey, ManyToOneRel
from django.core.management.color import no_style
from south.db.generic import DatabaseOperations, invalidate_table_constraints, flatten
def column_sql(self, table_name, field_name, field, tablespace='', with_name=True, field_prepared=False):
"""
Creates the SQL snippet for a column. Used by add_column and add_table.
"""
# If the field hasn't already been told its attribute name, do so.
...
...
...
if field.rel and self.supports_foreign_keys:
# HACK: "soft" FK handling begin
if not hasattr(field, 'no_db_constraints') or not field.no_db_constraints:
self.add_deferred_sql(
self.foreign_key_sql(
table_name,
field.column,
field.rel.to._meta.db_table,
field.rel.to._meta.get_field(field.rel.field_name).column
)
)
# HACK: "soft" FK handling end
# Things like the contrib.gis module fields have this in 1.1 and below
if hasattr(field, 'post_create_sql'):
for stmt in field.post_create_sql(no_style(), ta
....
....
# monkey patch South here
DatabaseOperations.column_sql = column_sql
Run Code Online (Sandbox Code Playgroud)
和:
from django.db.models.deletion import DO_NOTHING
from django.db.models.fields.related import ForeignKey, ManyToOneRel
from django.core.management.color import no_style
from south.db.generic import DatabaseOperations, invalidate_table_constraints, flatten
@invalidate_table_constraints
def alter_column(self, table_name, name, field, explicit_name=True, ignore_constraints=False):
"""
Alters the given column name so it will match the given field.
Note that conversion between the two by the database must be possible.
Will not automatically add _id by default; to have this behavour, pass
explicit_name=False.
@param table_name: The name of the table to add the column to
@param name: The name of the column to alter
@param field: The new field definition to use
"""
if self.dry_run:
if self.debug:
...
...
if not ignore_constraints:
# Add back FK constraints if needed
if field.rel and self.supports_foreign_keys:
# HACK: "soft" FK handling begin
if not hasattr(field, 'no_db_constraints') or not field.no_db_constraints:
self.execute(
self.foreign_key_sql(
table_name,
field.column,
field.rel.to._meta.db_table,
field.rel.to._meta.get_field(field.rel.field_name).column
)
)
# HACK: "soft" FK handling end
# monkey patch South here
DatabaseOperations.alter_column = alter_column
Run Code Online (Sandbox Code Playgroud)
这确实很难看,但我没有找到其他方法。
现在,您可以像普通外键一样使用 SoftForeignKey 字段,只是您不会执行任何引用完整性。
请参阅此处了解完整的猴子补丁:http://eve-corp-management.org/projects/ecm/repository/entry/ecm/lib/softfk.py
| 归档时间: |
|
| 查看次数: |
3773 次 |
| 最近记录: |