如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?
Posted
技术标签:
【中文标题】如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?【英文标题】:How do I create a Django model with ForeignKeys which does not cascade deletes to its children? 【发布时间】: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 忽略从我的视图中删除一行的命令而不是引发错误?
【问题讨论】:
【参考方案1】:Django 1.3a1 及以上版本通过 ForeignKey
的 on_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 忘记删除查询集。以上是关于如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 enumerable: false 不会级联到 TypeScript 中的继承类?