gpt4 book ai didi

django - 查找 M2M 项目中存在差异的同级记录

转载 作者:行者123 更新时间:2023-12-02 09:53:04 24 4
gpt4 key购买 nike

我需要查找两个子项(兄弟模型)中 Tags 存在差异的对象。

设置示例:

class Parent(models.Model):
pass

class Tag(models.Model):
name = models.CharField(max_length=256, unique=True)

class Child_OLD(models.Models):
parent = models.OneToOneField(Parent, ...)
tags = models.Many2ManyField(Tag)

class Child_NEW(models.Models):
parent = models.ForiegnKey(Parent, ...)
tags = models.Many2ManyField(Tag)

我想确保 Child_OLD 上的所有 Tags 记录都在 Child_NEW 记录中表示。具体来说,我希望使用比单独检查每个标签更快的方法来找到 Child_OLD 具有 Child_NEW 没有标签的任何父级。

我只对查找 child_old 具有 child_new 上没有的标签的 parent 感兴趣。这是一个完成类似事情的循环:

diffs = []
for parent in parents:
cn_tags = Tag.objects.filter(child_new__parent=parent)
qs_diff = parent.child_old.tags.all().difference(cn_tags)

if qs.exists():
diffs.append(parent.pk)

同样,我希望以更优化的方式使用查询集来执行此操作,因为迭代每个父项非常慢

大约有 1 亿多个“ parent ”和大约 500 个独特标签。一个典型的 child 会有 0-5 个标签

最佳答案

一种方法是过滤 Child_NEW 中的标签与 Child_OLD 中的标签相同并检查它们的计数是否与 Child_NEW 中所有标签的计数相同.

首先,最里面的子查询选择 Child_OLD 中的匹配标签:

criteria_sq = (Child_OLD.objects
.filter(parent=OuterRef(OuterRef('id')))
.values('tags__id')
)

然后将此子查询包装在另一个子查询中,以对 Child_NEW 中的匹配标签进行计数。 :

select_sq = (Child_NEW.objects
.filter(id=OuterRef('child_old__id'), tags__id__in=Subquery(criteria_sq, ))
.values('parent')
.annotate(tag_cnt=Count('parent'))
.values('tag_cnt')
)

这是最终的查询集。可以有重复的Parents如果超过一个Child_NEW指的是一个Parent .

qs = (Parent.objects
.annotate(tag_count_old=Count('child_old__tags'))
.annotate(tag_count_new=Subquery(select_sq, output_field=IntegerField()))
.filter(Q(tag_count_old__gt=F('tag_count_new')) | Q(tag_count_old__isnull=False, tag_count_new__isnull=True))
)
<小时/>

另一种解决方案是使用原始 SQL 在旧子/标签中间表和新子/标签中间表之间创建左联接,并选择右侧具有空值的父级。在此联接的每一侧,您都需要进一步对 a) 相应子表和 b) 父表进行内部联接,以便您可以联接父表 ID。

关于django - 查找 M2M 项目中存在差异的同级记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56009604/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com