Sometimes I’ll come across a situation where I have a QuerySet that has some default filters, such as, published products on a website. However, users may also want to include additional optional filters, for example, to filter for products that are on sale.
In this case, how could you create a Django QuerySet that has default filters, such as published=True
but can also accept optional filters passed via URL query parameters? For example, something like https://www.example.com?sale=true
.
Below is a simplified example of the technique I use for this.
from django.shortcuts import render
from products.models import Product
def products_list(request):
filters = {'published': True}
sale = request.GET.get('sale', None)
if sale == 'true':
filters['sale'] = True
products = Product.objects.filter(**filters)
return render(request, 'products.html', {'products': products})
Basically, you start by creating a dictionary of default filters. Then you check if the request has any expected query parameters, if they do then you append them to your filters dictionary. Finally, you use **
to unpack the dictionary items as keyword arguments into your model manager’s filter()
method.
This is a simple example, if you have many possible filters then your view code could become quite long, in which case you may want to abstract all of the if statements into a create_filters()
helper function. This could check the request for various expected query parameters and then return a dictionary object that can be unpacked into the filter()
method.
Not sure if anyone else has a better way of doing this but just thought I’d share.