如何根据Django orm中选择的manytomany匹配对象

How to match objects based on selected manytomany in Django orm

我正在尝试根据 ManyToMany 字段中的 selected/added 项获取对象。

我的模特:

class Location(models.Model):
    name = models.CharField(max_length=45)

class BenefitLocation(models.Model):
  benefit = models.ForeignKey(Benefit)
  location = models.ForeignKey(Location)

class Benefit(models.Model):
    locations = models.ManyToManyField(Location, through='BenefitLocation')

这是我在 orm 中尝试做的事情:

selected_locations = Location.objects.filter(id__in[1,2]) #Getting IDs from api request

matching_benefits = Benefit.objects.filter(locations=selected_locations)

在 matching_benefits 中,我只想要那些恰好位于这些选定位置的人。当我尝试我的代码时,出现此错误:django.db.utils.OperationalError: (1242, 'Subquery returns more than 1 row')

如何获得 matching_benefits?

编辑:

像这样使用@Willem Van Onsem 代码:​​

location_ids = [1]
location_ids = set(location_ids)

matching_benefits = Benefit.objects.annotate(
  nloc_count=Count('locations'),
  nloc_filter=Count('locations', filter=Q(locations__in=location_ids))
  ).filter(
  nloc_count=len(location_ids),
  nloc_filter=len(location_ids)
)

for item in matching_benefits:
  print(item.locations.values('id'))
  
#output
#<QuerySet [{'id': 1}]>
#<QuerySet [{'id': 2}]>

但是查询还是有两个好处(位置不同)

你应该使用 __in:

selected_locations = Location.objects.filter(id__in=[1,2])
matching_benefits = Benefit.objects.filter(<b>locations__in=selected_locations</b>)

但这里直接使用 id 列表更干净:

matching_benefits = Benefit.objects.filter(<b>locations__in=[1,2]</b>)

如果您正在寻找 Benefit 至少有 个所有这些位置,您可以使用:

进行过滤
from django.db.models import Sum

location_ids = [1, 2]
location_ids = set(location_ids)

matching_benefits = Benefit.objects.filter(
    <b>locations__in=location_ids</b>
).annotate(nloc=Count('locations')).filter(<b>nloc=len(location_ids)</b>)

对于 恰好 所有这些位置的 Benefit,您可以使用:

进行过滤
from django.db.models import Sum, Q

location_ids = [1,2]
location_ids = set(location_ids)

matching_benefits = Benefit.objects.annotate(
    nloc=Count('locations'),
    nloc_filter=Count('locations'<b>, filter=Q(locations__in=location_ids)</b>)
).filter(
    <b>nloc=len(location_ids)</b>,
    <b>nloc_filter=len(location_ids)</b>
)