목록의 * 모든 * 항목에 대한 Django 필터 쿼리 세트 __in
다음 모델이 있다고 가정 해 보겠습니다.
class Photo(models.Model):
tags = models.ManyToManyField(Tag)
class Tag(models.Model):
name = models.CharField(max_length=50)
보기에는 범주 라는 활성 필터가있는 목록이 있습니다. 카테고리에 모든 태그가있는 사진 개체를 필터링하고 싶습니다 .
나는 시도했다 :
Photo.objects.filter(tags__name__in=categories)
그러나이 일치 어떤 종류,하지에있는 항목 의 모든 항목을.
따라서 카테고리가 [ '휴일', '여름']이면 휴일과 여름 태그가 모두있는 사진을 원합니다.
이것이 달성 될 수 있습니까?
요약:
한 가지 옵션은 주석에서 jpic 및 sgallen이 제안한대로 .filter()
각 범주 에 추가하는 것 입니다. filter
추가 할 때 마다 더 많은 조인이 추가되므로 작은 범주 집합에는 문제가되지 않습니다.
가 집계 방식은 . 이 쿼리는 많은 범주 집합에 대해 더 짧고 더 빠를 수 있습니다.
사용자 지정 쿼리 를 사용할 수도 있습니다 .
몇 가지 예
테스트 설정 :
class Photo(models.Model):
tags = models.ManyToManyField('Tag')
class Tag(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
In [2]: t1 = Tag.objects.create(name='holiday')
In [3]: t2 = Tag.objects.create(name='summer')
In [4]: p = Photo.objects.create()
In [5]: p.tags.add(t1)
In [6]: p.tags.add(t2)
In [7]: p.tags.all()
Out[7]: [<Tag: holiday>, <Tag: summer>]
사용 체인 필터 접근 :
In [8]: Photo.objects.filter(tags=t1).filter(tags=t2)
Out[8]: [<Photo: Photo object>]
결과 쿼리 :
In [17]: print Photo.objects.filter(tags=t1).filter(tags=t2).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_photo_tags" T4 ON ("test_photo"."id" = T4."photo_id")
WHERE ("test_photo_tags"."tag_id" = 3 AND T4."tag_id" = 4 )
각각 은 쿼리에 filter
더 많은 JOINS
것을 추가 합니다.
주석 접근 방식 사용 :
In [29]: from django.db.models import Count
In [30]: Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2)
Out[30]: [<Photo: Photo object>]
결과 쿼리 :
In [32]: print Photo.objects.filter(tags__in=[t1, t2]).annotate(num_tags=Count('tags')).filter(num_tags=2).query
SELECT "test_photo"."id", COUNT("test_photo_tags"."tag_id") AS "num_tags"
FROM "test_photo"
LEFT OUTER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
WHERE ("test_photo_tags"."tag_id" IN (3, 4))
GROUP BY "test_photo"."id", "test_photo"."id"
HAVING COUNT("test_photo_tags"."tag_id") = 2
AND
ed Q
개체는 작동하지 않습니다.
In [9]: from django.db.models import Q
In [10]: Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
Out[10]: []
In [11]: from operator import and_
In [12]: Photo.objects.filter(reduce(and_, [Q(tags__name='holiday'), Q(tags__name='summer')]))
Out[12]: []
결과 쿼리 :
In [25]: print Photo.objects.filter(Q(tags__name='holiday') & Q(tags__name='summer')).query
SELECT "test_photo"."id"
FROM "test_photo"
INNER JOIN "test_photo_tags" ON ("test_photo"."id" = "test_photo_tags"."photo_id")
INNER JOIN "test_tag" ON ("test_photo_tags"."tag_id" = "test_tag"."id")
WHERE ("test_tag"."name" = holiday AND "test_tag"."name" = summer )
작동하는 또 다른 접근 방식은 PostgreSQL에만 해당되지만 django.contrib.postgres.fields.ArrayField
다음을 사용하는 것입니다 .
문서 에서 복사 한 예 :
>>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
>>> Post.objects.filter(tags__contains=['thoughts'])
<QuerySet [<Post: First post>, <Post: Second post>]>
>>> Post.objects.filter(tags__contains=['django'])
<QuerySet [<Post: First post>, <Post: Third post>]>
>>> Post.objects.filter(tags__contains=['django', 'thoughts'])
<QuerySet [<Post: First post>]>
ArrayField
오버랩 및 인덱스 변환 과 같은 더 강력한 기능이 있습니다 .
This also can be done by dynamic query generation using Django ORM and some Python magic :)
from operator import and_
from django.db.models import Q
categories = ['holiday', 'summer']
res = Photo.filter(reduce(and_, [Q(tags__name=c) for c in categories]))
The idea is to generate appropriate Q objects for each category and then combine them using AND operator into one QuerySet. E.g. for your example it'd be equal to
res = Photo.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
I use a little function that iterates filters over a list for a given operator an a column name :
def exclusive_in (cls,column,operator,value_list):
myfilter = column + '__' + operator
query = cls.objects
for value in value_list:
query=query.filter(**{myfilter:value})
return query
and this function can be called like that:
exclusive_in(Photo,'tags__name','iexact',['holiday','summer'])
it also work with any class and more tags in the list; operators can be anyone like 'iexact','in','contains','ne',...
If we want to do it dynamically, followed the example:
tag_ids = [t1.id, t2.id]
qs = Photo.objects.all()
for tag_id in tag_ids:
qs = qs.filter(tag__id=tag_id)
print qs
참고URL : https://stackoverflow.com/questions/8618068/django-filter-queryset-in-for-every-item-in-list
'program tip' 카테고리의 다른 글
Maven 종속성 spring-web 대 spring-webmvc (0) | 2020.09.10 |
---|---|
Android 4.4.2에서 Google API (x86 시스템 이미지)와 Google API (ARM 시스템 이미지)의 차이점 (0) | 2020.09.10 |
canvas.toDataURL ()에서 보안 예외가 발생하는 이유는 무엇입니까? (0) | 2020.09.10 |
먼저 쿼리하지 않고 레코드를 업데이트 하시겠습니까? (0) | 2020.09.10 |
FactoryGirl에서 빌드 및 생성 방법의 차이점은 무엇입니까? (0) | 2020.09.10 |