如何根据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>
)
我正在尝试根据 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>
)