在 Django 查询集中过滤不存在​​的 GenericForeignKey 对象

Filter non-existing GenericForeignKey objects in Django queryset

我有一个带有通用外键的简单模型:

class Generic(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

我想过滤此 table 中具有 非空 content_object 的所有条目,即过滤掉 [=] 的所有实例13=] 其 内容对象不再存在 :

Generic.objects.filter(~Q(content_object=None))

这不起作用,给出异常:

django.core.exceptions.FieldError: Field 'content_object' does not generate an automatic reverse relation and therefore cannot be used for reverse querying. If it is a GenericForeignKey, consider adding a GenericRelation.

向引用的内容类型模型添加 GenericRelation 没有任何区别。

任何有关如何实现此目的的帮助将不胜感激,非常感谢。

编辑:我知道我可以级联删除,但是在我的情况下这不是一个选项(我希望保留数据)。

如果要过滤掉一些记录out,通常使用exclude()方法比较好:

Generic.objects.exclude(object_id__isnull=True)

不过请注意,您的模型现在不允许空 content_object 字段。要更改此行为,use null=True 参数到 object_idcontent_type 字段。

更新

好的,由于问题已经从过滤掉空记录转变为在没有 RDBMS 本身帮助的情况下确定损坏的 RDBMS 引用,我建议一个(相当慢且需要内存的)解决方法:

broken_items = []
for ct in ContentType.objects.all():        
    broken_items.extend(
        Generic.objects
        .filter(content_type=ct)
        .exclude(object_id__in=ct.model_class().objects.all())
        .values_list('pk', flat=True))

这可以用作 one-time 脚本,但不是一个可靠的解决方案。如果你绝对想保留数据,我能想到的唯一快速方法是在你的 Generic 模型中有一个 is_deleted 布尔标志并将其设置在 (post|pre)_delete 信号中。