【问题标题】:Filter non-existing GenericForeignKey objects in Django queryset在 Django 查询集中过滤不存在​​的 GenericForeignKey 对象
【发布时间】:2016-05-03 05:55:43
【问题描述】:

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

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

我想过滤此表中所有具有非空 content_object 的条目,即过滤掉所有内容对象不再存在的Generic 实例:

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

这不起作用,给出异常:

django.core.exceptions.FieldError: 字段 'content_object' 没有 生成自动反向关系,因此不能使用 用于反向查询。如果是 GenericForeignKey,请考虑添加 泛型关系。

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

任何关于如何实现这一点的帮助将不胜感激,非常感谢。

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

【问题讨论】:

    标签: python django django-queryset django-generic-views django-contenttypes


    【解决方案1】:

    如果要过滤一些记录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))
    

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

    【讨论】:

    • 另一个人评论了这个相同的解决方案然后删除它,因为它不起作用,除了你的无效,因为这将检查 object_id 字段是否为空,而不是该 ID 引用的相关对象。无论哪种方式,如果您修复它仍然会给出与原始问题中发布的相同的异常。过滤或排除在这里没有区别。 FWIW 检查= Noneisnull=True 相同。
    • Ben,但是“非空”content_object 是什么意思呢?它只是数据库中两个实际字段的(足够薄的)包装器。如果您想排除 Generics 没有引用任何其他模型,我上面给出的查询就是有效的查询。或者请在答案中细化您对“空对象”的定义。
    • 嗨,Alex,我已经澄清了这个问题。 Non-null 表示您可以使用object_id 定义的ID 从content_type_id 定义的表中检索的实际对象。例如,如果您与现在已删除的对象有通用关系。
    • 好的,现在我明白了。看看我对它的最新想法。
    • 在第二个版本中,排除不应该在object_id而不是pk:.exclude(object_id__in=ct.model_class().objects.all())上吗? (因为pk 会引用Generic 自己的id,而不是您要检查的相关模型的id。)
    猜你喜欢
    • 1970-01-01
    • 2014-01-08
    • 2013-03-11
    • 2019-12-04
    • 2015-08-18
    • 2011-02-04
    • 2011-06-11
    • 1970-01-01
    相关资源
    最近更新 更多