当前位置:  开发笔记 > 编程语言 > 正文

Nullable ForeignKeys并删除引用的模型实例

如何解决《NullableForeignKeys并删除引用的模型实例》经验,为你挑选了1个好方法。

我有一个ForeignKey,在我的模型中可以为null,以模拟模型之间的松散耦合.看起来有点像:

class Message(models.Model):
  sender = models.ForeignKey(User, null=True, blank=True)
  sender_name = models.CharField(max_length=255)

保存时,发件人名称将写入sender_name属性.现在,我希望能够删除发件人引用的User实例并将消息保留在原位.

开箱即用,一旦删除User实例,此代码总是会导致删除的消息.所以我认为信号处理程序是个好主意.

def my_signal_handler(sender, instance, **kwargs):
  instance.message_set.clear()
pre_delete.connect(my_signal_handler, sender=User)

可悲的是,它绝不是一个解决方案.不知怎的,Django首先收集它想要删除的内容,然后触发pre_delete处理程序.

有任何想法吗?我脑子里的结是哪里的?



1> Jarret Hardi..:

Django确实模仿了SQL的ON DELETE CASCADE行为,并且没有开箱即用的文档来改变它.他们提到这个的文档接近本节的结尾:删除对象.

你是对的,Django收集所有相关的模型实例,然后为每个实例调用预删除处理程序.信号的发送者将是要删除的模型类,在这种情况下Message,而不是User,这使得很难检测到User触发的级联删除和正常删除之间的区别...特别是因为删除信号User类是最后一个,因为那是最后一次删除:-)

但是,您可以在调用User.delete()函数之前获取Django建议删除的对象列表.每个模型实例都有一个半私有方法_collect_sub_objects(),该方法使用指向它的外键编译实例列表(它编译此列表而不删除实例).你可以看到这种方法是通过看叫delete()django.db.base.

如果这是你自己的一个对象,我建议覆盖delete()你的实例上的方法来运行_collect_sub_objects(),然后在调用超类删除之前中断ForeignKeys.由于您使用的是内置的Django对象,您可能会发现它太难以进行子类化(尽管可以将您自己的User对象替换为django),您可能必须依赖视图逻辑来运行_collect_sub_objects并在删除之前中断FK .

这是一个快速而肮脏的例子:

from django.db.models.query import CollectedObjects
u = User.objects.get(id=1)


instances_to_be_deleted = CollectedObjects()
u._collect_sub_objects(instances_to_be_deleted)

for k in instances_to_be_deleted.ordered_keys():
    inst_dict = instances_to_be_deleted.data[k]
    for i in inst_dict.values():
        i.sender = None  # You will need a more generic way for this
        i.save()

u.delete()

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有