Python 过滤Django queryset中不存在的GenericForeignKey对象
我有一个带有通用外键的简单模型:Python 过滤Django queryset中不存在的GenericForeignKey对象,python,django,django-queryset,django-generic-views,django-contenttypes,Python,Django,Django Queryset,Django Generic Views,Django Contenttypes,我有一个带有通用外键的简单模型: class Generic(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey('content_type', 'object_id') 我想筛选此表中具有非空内容对象的所有条目,即筛选出其内容对象不再存在的通用的所
class Generic(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
我想筛选此表中具有非空内容对象的所有条目,即筛选出其内容对象不再存在的通用
的所有实例:
Generic.objects.filter(~Q(content_object=None))
这不起作用,出现以下例外情况:
django.core.exceptions.FieldError:字段“内容\对象”不存在
生成自动反向关系,因此无法使用
用于反向查询。如果它是通用的外键,请考虑添加
一般关系
将generirelation
添加到引用的内容类型模型中没有任何区别
任何关于如何实现这一点的帮助都将不胜感激,非常感谢
编辑:我意识到我可以级联删除,但在我的情况下这不是一个选项(我希望保留数据)。如果你想过滤掉一些记录,通常最好使用以下方法:
但是请注意,您的模型现在不允许空的content\u object
字段。要更改此行为,请使用object\u id
和content\u type
字段的null=True
参数
更新
好的,因为问题已经从过滤空记录转移到在没有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))
这将作为一次性脚本工作,但不是一个健壮的解决方案。如果你绝对想保留数据,我能想到的唯一快速方法是在你的通用模型中设置is\u deleted
布尔标志,并将其设置为(post | pre)\u delete
信号。另一个人评论了同样的解决方案,然后删除了它,因为它不起作用,除非你的是无效的,因为这将检查对象\u id
字段是否为空,而不是该id引用的相关对象。无论哪种方式,如果你修复了它,它仍然会给出与原始问题中发布的相同的异常。过滤或排除在这里没有区别。FWIW checking=None
与isnull=True
.Ben相同,但是“non-null”content\u object
意味着什么?它只是数据库中两个实际字段的(足够薄)包装器。如果您想排除没有引用任何其他模型的泛型,我上面给出的查询就是有效的查询。或者请细化您对回答中的“空对象”。嗨,亚历克斯,我已经澄清了这个问题。非空表示可以使用object\u id
定义的id从content\u type\u id
定义的表中检索的实际对象。例如,如果你和一个已经被删除的对象有一个泛型关系。好的,现在我明白了。看看我对它的最新想法。在第二个版本中,排除不是应该在object\u id
而不是pk
:.exclude(object\u id\u In=ct.model\u class().objects.all())
?(因为pk
将引用Generic
自己的id,而不是要检查的相关型号的id。)
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))