Django filter multiple values

Question:

Anyone know why this query_set doesn’t return any values for me? Using filter separately, it works perfectly, so it seems .filter().filter() together is the wrong approach to filter for ‘either or’.

ticket_query = request.event.tickets.filter(status='on-sale').filter(status='paused').prefetch_related('ticket_tax')
Asked By: user9252255

||

Answers:

filter() with multiple parameters joins them with AND statements:
https://docs.djangoproject.com/en/2.0/ref/models/querysets/#filter

To perform OR queries in django you can use Q objects:

from django.db.models import Q

ticket_query = request.event.tickets.filter(Q(status='on-sale') | Q(status='paused')).prefetch_related('ticket_tax')

More details here:
https://docs.djangoproject.com/en/2.0/topics/db/queries/#complex-lookups-with-q

Answered By: phil

Chaining filter like you have done applies the subsequent filter to the queryset returned by the previous filter, i.e. it acts like an AND condition, not OR.

You can use the | operator to combine two queries:

ticket_query = request.event.tickets.filter(status='on-sale') | request.event.tickets.filter(status='paused')
Answered By: iacob

request.event.tickets.filter(status='on-sale') returns all objects with status='on-sale', and you are looking for objects with status='paused' in that list, which is why you are getting an empty queryset.

Chaining 2 filters is fine if it is a ManyToManyField where you can have multiple objects for the same field OR if you are chaining for 2 separate fields eg. request.event.tickets.filter(status='on-sale').filter(is_available=True), which returns all tickets that are on sale and are available.

The simplest approach for this problem would be to use __in in the filter like this: ticket_query = request.event.tickets.filter(status__in=['on-sale', 'paused']).prefetch_related('ticket_tax').

Hope this helps. 🙂

Answered By: Ruhi123
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.