如何使用外键创建一个Django模型,它不会将删除级联到其子项?

时间:2009-06-17 10:07:43

标签: mysql django django-models

我的一个拥有ForeignKey的模型实际上是其他表上的MySQL视图。我遇到的问题是,当我从这些表中删除数据时,Django,如"deleting objects" documentation ...

中所述
  

当Django删除一个对象时,它   模拟SQL的行为   约束ON DELETE CASCADE - in   换句话说,任何具有的对象   指向对象的外键   被删除将被删除   它

...尝试从我的视图中删除行,当然它不能,所以抛出错误:

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

有没有办法在模型上指定一个ForeignKey约束,它将为我提供所有Django魔法,但是不会将删除级联到它上面?或者,有没有办法让MySQL忽略从我的视图中删除行而不是引发错误的命令?

7 个答案:

答案 0 :(得分:23)

Django 1.3a1并通过ForeignKey的{​​{3}}论证提供支持。

以下示例在删除外键时设置字段NULL。有关更多选项,请参阅on_delete

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

答案 1 :(得分:18)

哈罗德的回答指出了我正确的方向。这是我实现它的方式草图(在法国遗留数据库上,因此有点奇怪的命名约定):

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()

答案 2 :(得分:7)

Django的ForeignKey管理器有一个名为clear()的方法,它从相关的对象集中删除所有对象。首先调用,然后删除您的对象应该工作。依赖对象的外键设置为None(如果模型允许)。

这里有一个简短的描述: http://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward

答案 3 :(得分:3)

仅供参考 - 在http://code.djangoproject.com/ticket/7539的django源存储库中存在对此的功能请求。看起来这个主题得到了一些关注。希望它将包含在未来的Django版本中。

该票据包括Django核心的补丁,用于为models.ForeignKey(...)实现“on_delete”可选参数,该参数允许您指定在删除指向模型时发生的情况,包括关闭默认的ON DELETE CASCADE行为

答案 4 :(得分:2)

好吧,看看删除方法

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)

答案 5 :(得分:1)

一种方法是在删除之前调用clear方法,documentation here基本上“清除”关系。 一个问题是:它本身不是汽车。你可以选择:每次你不想要级联时调用它,或者在每次删除之前使用pre_delete信号发送清除,当然它会在你想要删除时给你带来问题 - 级联。

或者你可以为django社区做贡献并添加关键字参数来删除,也许它会在django 1.3中?:D

答案 6 :(得分:0)

回复:http://code.djangoproject.com/ticket/7539

2010年6月的Django 1.2.1没有引起注意。我想我们需要“注意那个空间”。