Programming/Django

[Django] AND 조건 filter

stein 2022. 1. 19. 11:53

https://stackoverflow.com/questions/8618068/django-filter-queryset-in-for-every-item-in-list

 

Django filter queryset __in for *every* item in list

Let's say I have the following models class Photo(models.Model): tags = models.ManyToManyField(Tag) class Tag(models.Model): name = models.CharField(max_length=50) In a view I have a lis...

stackoverflow.com

TL;DR

queryset = models.Post.objects.filter(
                categories__in=category_objects)
                .annotate(num_categories=Count('categories'))
                .filter(num_categories=len(category_names))
            # categories__in: get every posts matched any of category in category_objects
            # annoate: make a num_categories annotation(as a field) with Count of categories
            # filter(again): filter posts have exact number of category_names

 

사용한 코드

 

설명

위 stackoverflow는 총 3가지의 방식을 설명해준다.

 

1. filter를 따로따로 연속으로 걸어주기

2. annotation을 사용하기

3. 커스텀 쿼리 사용하기

One option is, as suggested by jpic and sgallen in the comments, to add .filter() for each category. Each additional filter adds more joins, which should not be a problem for small set of categories.

There is the aggregation approach. This query would be shorter and perhaps quicker for a large set of categories.

You also have the option of using custom queries.

 

1번 방식은 직관적이지만 filter해야할 요소가 dynamic하게 변할 때는 사용하기 힘들다. 필자는 2번 방식을 사용하였다.(큰 set에 대해서 성능도 더 좋다고 한다!)

 

코드

queryset = models.Post.objects.filter(
                categories__in=category_objects)
                .annotate(num_categories=Count('categories'))
                .filter(num_categories=len(category_names))


1. models.Post.objects.filter(categories__in=category_objects)

object로 해당하는 모든 post를 가져온다(or 조건)

 

2. .annotate(num_categories=Count('categories'))

categories의 개수를 num_categories라는 annotation(주석)으로 붙인다. field처럼 생각하면 될 것 같다.

https://docs.djangoproject.com/en/dev/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset

 

Aggregation | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

3. .filter(num_categories=len(category_names))

생성한 annotation으로 검색할 category의 개수와 동일한 categories를 가진 post만 꺼내도록 filter를 걸어준다.

 

조금 신선한 방식이라 생각한다(나만 그런가?). AND option을 만들어 놓았을 것 같은데 그게 아니라 개수로 찾다니..! 신기해서 포스팅을 남긴다.