Как создать модель Django с ForeignKeys, которая не осуществляет каскадное удаление своих дочерних элементов? - PullRequest
23 голосов
/ 17 июня 2009

Одной из моих моделей, которая имеет ForeignKey, на самом деле является представление MySQL для других таблиц. Проблема, с которой я сталкиваюсь, заключается в том, что, когда я удаляю данные из этих таблиц, Django, как описано в документации «Удаление объектов» ...

Когда Django удаляет объект, он эмулирует поведение SQL ограничение НА УДАЛИТЬ КАСКАД - в Другими словами, любые объекты, которые имели внешние ключи, указывающие на объект быть удален будет удален вместе с это.

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

mysql_exceptions.OperationalError '>=(1395, "Can not delete from join view 'my_db.my_mysql_view'"'

Есть ли способ указать ограничение ForeignKey для модели, которое предоставит мне все волшебство Django, но не будет каскадно удалять его? Или есть ли способ попросить MySQL игнорировать команды для удаления строки из моего представления вместо сообщения об ошибке?

Ответы [ 7 ]

23 голосов
/ 11 ноября 2010

Django 1.3a1 и выше поддерживают это с помощью ForeignKey 's on_delete аргумента.

В следующем примере устанавливается поле NULL при удалении внешнего ключа. См. документацию для получения дополнительной информации.

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)
18 голосов
/ 24 сентября 2009

Ответ Гарольда указал мне правильное направление. Это набросок того, как я его реализовал (для французской устаревшей базы данных, отсюда и немного странное соглашение об именах):

class Factures(models.Model):
    idFacture = models.IntegerField(primary_key=True)
    idLettrage = models.ForeignKey('Lettrage', db_column='idLettrage', null=True, blank=True)

class Paiements(models.Model):
    idPaiement = models.IntegerField(primary_key=True)
    idLettrage = models.ForeignKey('Lettrage', db_column='idLettrage', null=True, blank=True)

class Lettrage(models.Model):
    idLettrage = models.IntegerField(primary_key=True)

    def delete(self):
        """Dettaches factures and paiements from current lettre before deleting"""
        self.factures_set.clear()
        self.paiements_set.clear()
        super(Lettrage, self).delete()
7 голосов
/ 17 июня 2009

Менеджер ForeignKey в Django имеет метод clear (), который удаляет все объекты из набора связанных объектов. Сначала вызов этого, а затем удаление вашего объекта должно сработать. Внешним ключам зависимых объектов будет присвоено значение Нет (если это разрешено в вашей модели).

Краткое описание здесь: http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward

3 голосов
/ 02 января 2010

FYI - запрос функции для этого существует в репозитории исходного кода django по адресу http://code.djangoproject.com/ticket/7539. Похоже, что этой теме уделяется некоторое внимание. Надеюсь, он будет включен в будущие релизы Django.

Билет включает в себя исправления для ядра Django для реализации необязательного параметра on_delete для моделей. ForeignKey (...), который позволяет вам указать, что происходит, когда указанная модель удаляется, включая отключение поведения по умолчанию ON DELETE CASCADE. .

2 голосов
/ 17 июня 2009

Ну, глядя на метод удаления

def delete(self):
    assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)

    # Find all the objects than need to be deleted.
    seen_objs = CollectedObjects()
    self._collect_sub_objects(seen_objs)

    # Actually delete the objects.
    delete_objects(seen_objs)

Я бы сказал, что для удаления должно быть достаточно ... непроверенный код будет

def delete(self):
    assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)

    # Find all the objects than need to be deleted.
    seen_objs = CollectedObjects()
    seen_objs.add(model=self.__class__, pk=self.pk, obj=self, parent_model=None)

    # Actually delete the objects.
    delete_objects(seen_objs)
1 голос
/ 14 сентября 2009

Один из способов - вызвать метод clear перед удалением, документация здесь , которая в основном "очищает" связь. Одна проблема подумала: это не само по себе. Вы можете выбрать: вызывать его каждый раз, когда вам не нужен каскад, или использовать сигнал pre_delete для отправки очистки перед каждым удалением, конечно, это создаст вам проблемы, когда вы действительно хотите удалить - каскад.

Или вы можете внести свой вклад в сообщество django и добавить аргумент ключевого слова для удаления, может быть, это будет в django 1.3?: D

0 голосов
/ 24 июня 2010

Re: http://code.djangoproject.com/ticket/7539

Никакого внимания с Django 1.2.1, июнь 2010 года. Я думаю, нам нужно "наблюдать за этим пространством".

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