呦傢伙,
我設法讓我想要的東西。
首先,我創建了一個新的領域:
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
由於我使用南來管理我的數據庫架構,我不得不補充一點:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], [r'^ecm\.lib\.softfk\.SoftForeignKey'])
於是,我只好猴子向南補丁,以便將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
和:
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
這實在是太醜了,但我沒有找到另一種方式。
現在您可以使用SoftForeignKey字段完全像正常的ForeignKey字段,除了您不會有任何參考完整性實施。
在這裏看到完整的猴子補丁:http://eve-corp-management.org/projects/ecm/repository/entry/ecm/lib/softfk.py
那麼它不是一個真正的外鍵,是嗎? –
那麼我想從沒有db約束的django ForeignKey的所有功能中受益。 – Robin
例如,我希望能夠從該SoftForeignKey引用的表中刪除一行,而不必級聯或將鍵設置爲NULL。如果一個對象有一個對目標表中不存在的行的引用,它應該引發一個'ObjectDoesNotExist'異常。但我希望數據庫接受這種狀態。 – Robin