Django无法级联删除相关的通用外键对象

Django failing to cascade-delete related generic foreign key object

我在我的模型中定义了以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TaskLink(models.Model):
    task = model.ForeignKey(Task)
    link_choices = (
        models.Q(app_label="accounts", model="location"),
        # Other models are also linked to here.
    )
    linked_content_type = \
        models.ForeignKey(
            ContentType,
            limit_choices_to=link_choices
        )
    linked_object_id = models.PositiveIntegerField()
    linked_object = \
        generic.GenericForeignKey(
            'linked_object_content_type',
            'linked_object_id'
        )

这个模型将Task对象与link_choices元组中的任何模型链接起来。在这种情况下,accounts.Location模型在此列表中。

当删除一个Location对象导致相关TaskLink对象的级联删除时,我的问题出现了。删除失败,并显示以下错误消息:

1
django.core.exceptions.FieldError: Cannot resolve keyword 'object_id' into field. Choices are: id, linked_object, linked_object_content_type, linked_object_content_type_id, linked_object_id, task, task_id

该视图是django.views.generic.DeleteView的一个实例,只有pk_url_kwarg参数和模型集(以及在分派方法中添加的权限修饰符);在我将TaskLink模型添加到组合中之前,它工作得很好。

我错过了什么?

编辑:这似乎是Django中的一个bug;当通过通用外键级联删除对象时,Django忽略了您传递给GenericForeignKey字段的构造函数的字段名字符串,而是查找不存在的content_typeobject_id字段。这有效地限制了模型可能必须1的通用外键的数量,除非您不会遇到级联删除。

我已经通过django邮件列表发送了这个问题,因为这种行为可能是有意的。


重命名tasklink的字段名

1
2
linked_content_type >>> content_type
linked_object_id >>> object_id

或者在删除"location"对象时写入预信号删除链接对象"tasklink"

1
2
3
4
5
6
7
8
from django.db.models.signals import pre_delete
from django.dispatch import receiver

@receiver(pre_delete, sender=Location, dispatch_uid='location_delete_signal')
def deleted_gfk_TaskLink(sender, instance, using, **kwargs):
    ctype = ContentType.objects.get_for_model(sender)
    obj = TaskLink.objects.get(linked_content_type=ctype, linked_object_id=instance.id)
    obj.delete()

自定义信号参考:https://micropyramid.com/blog/using-djangos-built-in-signals-and-writing-custom-signals/