목록의 *모든* 항목에 대한 장고 필터 쿼리 집합 __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)
그러나 이것은 모든 항목이 아니라 범주의 모든 항목과 일치합니다.
그래서 만약 카테고리가 ['holiday', 'summer'라면 저는 휴일과 여름 태그가 모두 있는 사진을 원합니다.
이것이 달성될 수 있습니까?
요약:.
한 가지 옵션은 댓글에서 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
에드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 )
Postgre가 작동하는 또 다른 접근 방식SQL 전용, 사용 중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
에는 중첩 및 인덱스 변환과 같은 보다 강력한 기능이 있습니다.
이것은 장고 ORM과 일부 파이썬 매직을 사용한 동적 쿼리 생성으로도 가능합니다 :)
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]))
이 아이디어는 각 범주에 적합한 Q 개체를 생성한 다음 AND 연산자를 사용하여 이들을 하나의 쿼리 집합으로 결합하는 것입니다. 예를 들어, 다음과 같습니다.
res = Photo.filter(Q(tags__name='holiday') & Q(tags__name='summer'))
주어진 연산자의 열 이름에 대해 목록 위에 필터를 반복하는 작은 함수를 사용합니다.
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
그리고 이 함수는 다음과 같이 부를 수 있습니다.
exclusive_in(Photo,'tags__name','iexact',['holiday','summer'])
또한 모든 클래스 및 목록의 더 많은 태그와 함께 작동합니다. 연산자는 'iexact', 'in', 'in', 'in', 'ne',...
만약 당신이 나처럼 이 문제에 어려움을 겪었지만 아무 것도 당신에게 도움이 되지 않았다면, 아마도 이것이 당신의 문제를 해결할 것입니다.
필터를 연결하는 대신 일부 경우에는 이전 필터의 ID만 저장하는 것이 좋습니다.
tags = [1, 2]
for tag in tags:
ids = list(queryset.filter(tags__id=tag).values_list("id", flat=True))
queryset = queryset.filter(id__in=ids)
이 접근 방식을 사용하면 스택을 방지할 수 있습니다.JOIN
SQL 쿼리에서:
내 해결책: 작성자가 목록의 모든 항목과 일치해야 하는 요소의 목록이라고 가정하면 다음과 같습니다.
for a in author:
queryset = queryset.filter(authors__author_first_name=a)
if not queryset:
break
for category in categories:
query = Photo.objects.filter(tags_name=category)
이 코드 조각은 카테고리에서 오는 모든 태그 이름을 가진 사진을 필터링합니다.
동적으로 실행하려면 다음과 같이 하십시오.
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
queryset = Photo.objects.filter(tags__name="vacaciones") | Photo.objects.filter(tags__name="verano")
언급URL : https://stackoverflow.com/questions/8618068/django-filter-queryset-in-for-every-item-in-list
'programing' 카테고리의 다른 글
매개 변수가 있는 PHP 생성자 (0) | 2023.07.26 |
---|---|
외부 Javascript 파일에서 PHP var 액세스 (0) | 2023.07.26 |
Oracle SQL 개발자에서 사용자를 생성하는 방법 (0) | 2023.07.26 |
jQuery has Class() - 둘 이상의 클래스를 확인합니다. (0) | 2023.07.26 |
Numpy: 첫 번째 값 인덱스를 빠르게 찾습니다. (0) | 2023.07.26 |