多FK属性查询集过滤

2024-05-12 22:46:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我的情况:

我有django model主机和model(带名称和版本),其中主机上有FK。现在我需要过滤所有主机,这些主机有,其中包含特定的名称和特定的版本。。因此类似于Host.objects.filter(name="best_package", version__in=['1.0','2.0']) 这一切都很好,也很简单,但我需要对几个包重复这个操作,这样我就可以得到一个主机,它在其中一个版本中拥有所需的每个包

我尝试了两种方法,但都失败了,第一种方法是在for循环中应用上面的过滤器,虽然很难看,但效果很好,尽管我很高兴,但我发现这不是稳定的解决方案,我接下来应用的一些查询有时会失败。。是的,有时候!正如我对自己所说的,我不会深入到Django ORM魔法的洞里,我试图用Q来构建查询

pckgs_query = reduce(
    operator.and_,
    (
        Q(packages__name=name, packages__version__in=versions)
        for name, versions in pckgs_dict.items()
    )
 )
hosts = Host.objects.filter(pckgs_query)

但不幸的是,这无法正常工作,因为我检查了它生成的SQL查询,我确信它正在查找包含所有这些参数的单个包对象,这些参数当然不存在。。。有没有足够熟练的人帮我一把?真的在这里迷失了方向,希望我的应用程序现在不在django tbh中

谢谢


Tags: django方法namein版本名称hostfor
1条回答
网友
1楼 · 发布于 2024-05-12 22:46:37

这不起作用的原因是,您每次都限制同一个包。如果键是'best_package''other_package',您会说应该有一个相关的包,它同时具有'best_package''other_package',但是由于包只有一个名称,这当然会失败

我们可以用另一种方法解决这个问题:我们首先过滤包以检索与字典中的条目匹配的所有,然后计数这些包,从而检查相关包的数量是否与字典中的元素数量相同:

from django.db.models import Count, Q

pckgs_query = Q(
    *[Q(package_set__name=name, package_set__version__in=versions)
      for name, versions in pckgs_dict.items()],
    _connector=Q.OR
)

hosts = Host.objects.filter(pckgs_query).annotate(
    num_packages=Count('package_set')
).filter(
    num_packages=len(pckgs_dict)
)

因此,这将只返回安装了所有包的Host,因为如果包丢失,那么num_packages将小于len(pckgs_dict)

相关问题 更多 >