Django ForeignKey, который не требует ссылочной целостности? - PullRequest
8 голосов
/ 24 августа 2010

Я хотел бы установить поле ForeignKey в модели django, которое иногда указывает на другую таблицу. Но я хочу, чтобы все было в порядке, чтобы вставить идентификатор в это поле, которое ссылается на запись в другой таблице, которая может отсутствовать. Поэтому, если строка существует в другой таблице, я хотел бы получить все преимущества отношения ForeignKey. Но если нет, я бы хотел, чтобы это воспринималось как число.

Возможно ли это? Для этого нужны родовые отношения?

Ответы [ 5 ]

7 голосов
/ 28 февраля 2014

Этот вопрос задавался давно, но для новичков теперь есть встроенный способ справиться с этим, установив db_constraint = False на ForeignKey:

https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.ForeignKey.db_constraint

customer = models.ForeignKey('Customer', db_constraint=False)

или если вы хотите быть обнуляемым, а также не применять ссылочную целостность:

customer = models.ForeignKey('Customer', null=True, blank=True, db_constraint=False) 

Мы используем это в тех случаях, когда мы не можем гарантировать, что отношения будут созданы в правильном порядке.

РЕДАКТИРОВАТЬ: обновить ссылку

3 голосов
/ 27 апреля 2013

Чтобы выполнить решение @Glenn Maynard через Юг, создайте пустую миграцию на юг:

python manage.py schemamigration myapp name_of_migration --empty

Отредактируйте файл миграции и запустите его:

def forwards(self, orm):
    db.delete_foreign_key('table_name', 'field_name')

def backwards(self, orm):
    sql = db.foreign_key_sql('table_name', 'field_name', 'foreign_table_name', 'foreign_field_name')
    db.execute(sql)

Источник статьи

3 голосов
/ 30 сентября 2010

Это, вероятно, так же просто, как объявить ForeignKey и создать столбец, фактически не объявляя его как FOREIGN KEY.Таким образом, вы получите o.obj_id, o.obj будет работать, если объект существует, и - я думаю, - вызвать исключение, если вы попытаетесь загрузить объект, который на самом деле не существует (вероятно, DoesNotExist).

Однако я не думаю, что есть способ заставить syncdb сделать это для вас.Я обнаружил, что syncdb является ограничением до такой степени, что он бесполезен, поэтому я полностью обошел его и создал схему со своим собственным кодом.Вы можете использовать syncdb для создания базы данных, а затем напрямую изменять таблицу, например.ALTER TABLE tablename DROP CONSTRAINT fk_constraint_name.

Вы также неизбежно теряете ON DELETE CASCADE и, конечно, все проверки ссылочной целостности.

3 голосов
/ 24 августа 2010

Я новичок в Django, так что я не буду сейчас, если он предоставляет то, что вы хотите из коробки. Я думал о чем-то вроде этого:

from django.db import models

class YourModel(models.Model):
    my_fk = models.PositiveIntegerField()

    def set_fk_obj(self, obj):
        my_fk = obj.id

    def get_fk_obj(self):
        if my_fk == None:
            return None
        try:
            obj = YourFkModel.objects.get(pk = self.my_fk)
            return obj
        except YourFkModel.DoesNotExist:
            return None

Я не знаю, используете ли вы приложение для администраторов Contribute. При использовании PositiveIntegerField вместо ForeignKey поле будет отображаться с текстовым полем на сайте администратора.

1 голос
/ 01 октября 2010

(Примечание: может быть полезно, если вы объясните, почему вы этого хотите. Возможно, есть лучший способ решения основной проблемы.)

Возможно ли это?

Не только с ForeignKey, поскольку вы перегружаете значения столбцов двумя разными значениями, без надежного способа их различения. (Например, что произойдет, если новая запись в целевой таблице будет создана с первичным ключом, совпадающим со старыми записями в ссылочной таблице? Что будет с этими старыми ссылочными записями при удалении новой целевой записи?)

Обычное специальное решение этой проблемы состоит в том, чтобы определить столбец типа или тега рядом с внешним ключом, чтобы различать различные значения (но см. Ниже).

Для этого нужны родовые отношения?

Да, частично.

GenericForeignKey - просто вспомогательный помощник Django для вышеприведенного шаблона; он связывает внешний ключ с тегом типа, который определяет, к какой таблице / модели он относится (используя соответствующий ContentType модели; см. contenttypes )

Пример: * * один тысяча двадцать-одна

class Foo(models.Model):

    other_type = models.ForeignKey('contenttypes.ContentType', null=True)
    other_id = models.PositiveIntegerField()
    # Optional accessor, not a stored column
    other = generic.GenericForeignKey('other_type', 'other_id')

Это позволит вам использовать other как ForeignKey, чтобы ссылаться на экземпляры вашей другой модели. (В фоновом режиме GenericForeignKey получает и устанавливает other_type и other_id для вас.)

Чтобы представить число, которое не является ссылкой, вы должны установить other_type на None и просто использовать other_id напрямую. В этом случае попытка доступа к other всегда будет возвращать None вместо повышения DoesNotExist (или возврата непреднамеренного объекта из-за столкновения идентификатора).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...