Yo Leute,
Ich konnte machen, was ich wollte.
Zuerst habe ich ein neues Feld erstellt:
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
Da ich Süden verwenden, um mein Datenbank-Schema zu verwalten, ich dies hinzugefügt hatte:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], [r'^ecm\.lib\.softfk\.SoftForeignKey'])
Dann musste ich Affen Patch Süden, so dass es den Parameter berücksichtigt. Es gab zwei in der Schaffung von FK Einschränkungen beteiligten Funktionen:
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
Und:
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
Das ist wirklich hässlich, aber ich habe nicht einen anderen Weg finden.
Jetzt können Sie das SoftForeignKey-Feld genau wie einen normalen ForeignKey verwenden, außer dass Sie keine referenzielle Integritätserzwingung haben.
Sehen Sie hier für den kompletten Affen-Patch: http://eve-corp-management.org/projects/ecm/repository/entry/ecm/lib/softfk.py
Es ist nicht wirklich ein Fremdschlüssel dann, innit? –
Nun möchte ich von allen Funktionen des django ForeignKey ohne die db-Einschränkung profitieren. – Robin
Zum Beispiel, ich möchte in der Lage sein, eine Zeile aus einer Tabelle zu löschen, die von diesem 'SoftForeignKey' referenziert wird, ohne eine Kaskade zu erzeugen oder den Schlüssel auf' NULL' zu setzen. Und wenn ein Objekt einen Verweis auf eine nicht vorhandene Zeile in der Zieltabelle hat, sollte es eine "ObjectDoesNotExist" -Ausnahme auslösen. Aber ich möchte, dass die Datenbank diesen Zustand akzeptiert. – Robin