【问题标题】:How do I create a Django model with ForeignKeys which does not cascade deletes to its children?如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?
【发布时间】:2010-11-03 14:48:16
【问题描述】:

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

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

...尝试从我的视图中删除行,这当然不能,因此会引发错误:

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

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

【问题讨论】:

    标签: mysql django django-models


    【解决方案1】:

    Django 1.3a1 及以上版本通过 ForeignKeyon_delete 参数支持此功能。

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

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

    【讨论】:

      【解决方案2】:

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

      从 2010 年 6 月的 Django 1.2.1 开始没有关注。我想我们需要“注意那个空间”。

      【讨论】:

        【解决方案3】:

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

        票证包括 Django 核心的补丁,用于实现 models.ForeignKey(...) 的“on_delete”可选参数,让您指定删除指向的模型时会发生什么,包括关闭默认的 ON DELETE CASCADE 行为.

        【讨论】:

        • 是的 - 它已经发布到 1.3 -> docs.djangoproject.com/en/dev/releases/1.3-alpha-1/#configurable-delete-cascade
        • 感谢@stevejalim 的更新。好消息。我想要这个功能很久了。
        【解决方案4】:

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

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

        【讨论】:

        • on_delete=models.SET_NULL : docs.djangoproject.com/en/1.4/ref/models/fields/#foreignkey(sinze 1.3 版本)
        • 为什么SET_NULL 会提供帮助? UPDATE将外键设置为 NULL 的视图仍然会引发异常。 models.DO_NOTHING 确实有帮助。
        • 添加null=True 后仍然出现错误。按照下面的 zourtney 建议添加 on_delete=models.SET_NULL 就可以了。
        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

            嗯,看看删除方法

            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)
            

            【讨论】:

            • (是的,这有点乱;我想说 ForeignKey 应该有参数...在 Django 票务系统中为它填写一个功能请求;))无论如何,对于您的看法,看看这个错误/补丁:code.djangoproject.com/ticket/10829
            • 忘记删除查询集。
            猜你喜欢
            • 2016-12-13
            • 1970-01-01
            • 2013-01-17
            • 1970-01-01
            • 1970-01-01
            • 2021-12-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多