Django:“Soft” ForeignField没有数据库完整性检查 [英] Django: "Soft" ForeignField without database integrity checks
问题描述
我有一个Django项目,有多个django应用程序。其中一个有模型来表示来自外部源的数据(我不控制这个数据)。
I have a Django project that has multiple django "apps". One of them has models to represent data coming from an external source (I do not control this data).
我想让其他应用程序能够引用这个外部应用程序,但我想避免所有的数据库完整性检查的毛刺。我不希望数据库对这些外键有任何约束。
I want my other apps to be able to have references to this "external app" but I want to avoid all the fuzz of the database integrity checks. I don't want the db to have any constraints on these "soft foreign keys".
你知道我如何编写一个自定义字段来模拟一个真正的Django ForeignKey没有在数据库上创建硬约束?
Do you know how I can code a custom field that will emulate a real Django ForeignKey without creating a hard constraint on the database?
也许这已经存在,但我没有在谷歌运气。
Maybe this already exists, but I didn't have any luck on Google.
感谢您的帮助: - )
Thanks in advance for the help :-)
注意:我知道通用关系系统与content_types。但我不想要泛型关系。
NB: I'm aware of the generic relations system with the content_types. But I don't want generic relations. I want specific relations to identified models only without hard integrity constraints.
编辑:
我发现相关链接:
但我没有找到一个正确的答案,我的问题。 :(
But I didn't find a proper answer to my question. :(
EDIT 2012,6月4日:
EDIT 2012, june 4:
我深入研究django的代码,但我认为只是简单地子类化ForeignKey是不够的,你能给我一些指导如何做这个吗?
I've looked deep into django's code to find what needs to be done, but I think that simply subclassing ForeignKey will not be enough. Could you give me some directions on how to do this?
注意:我使用South来管理我的数据库模式,所以我想我也需要做一些事情,但它可能是在这里的主题:)
NB: I use South for managing my database schema, so I figure I'll need to do something about that too. But it may be out of the subject here :)
推荐答案
Yo guys,
我设法做出了我想要的。
I managed to make what I wanted.
新字段:
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
b $ b
由于我使用South管理我的数据库模式,我不得不添加:
Since I use South to manage my database schema, I had to add this:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], [r'^ecm\.lib\.softfk\.SoftForeignKey'])
然后,我不得不猴子补丁,以便它考虑 no_db_constraints
参数。有两个函数涉及创建FK约束:
Then, I had to monkey patch south so that it takes the no_db_constraints
parameter into account. There were two functions involved in the creation of FK constraints:
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
和:
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
真的很丑,但我没有找到另一种方式。
This is really ugly but I didn't find another way.
现在你可以使用SoftForeignKey字段,就像一个普通的ForeignKey,只是你不会有任何引用的完整性。
Now you can use the SoftForeignKey field exactly like a normal ForeignKey except that you won't have any referencial integrity enforcement.
查看完整的猴子补丁: http://eve-corp-management.org/projects/ecm/repository/entry/ecm/lib/softfk.py
See here for the complete monkey-patch : http://eve-corp-management.org/projects/ecm/repository/entry/ecm/lib/softfk.py
这篇关于Django:“Soft” ForeignField没有数据库完整性检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!