We all know that we can use Django ORM as a high-level interface to interact with databases. And we can use normal methods like
filter() to narrow down our search.
But, there comes a stage in our project that it becomes tedious to handle looong lines and chains of filtering. Such as:
# Get the countries with name that starts with N or ends with L countries = Country.objects.filter(name__istartswith="N") | Country.objects.filter(name__iendswith="l") # Django querysets support & as and and | as or.
Here is where Q object makes an entry.
Q objects, we can use
~ as and, or, and not.
Let's see an example:
from django.db.models import Q countries = Country.objects.filter( Q(name__istartswith='N') | Q(name__iendswith='l') )
This was a rather simple example that shows how we can use
Q objects to simplify how we write queries.
Now, let's see how we can simplify a somewhat complex query using Q objects.
Here, we will use the same example of countries. But let's make our logic a bit complex. Like:
Get countries that satisfy both of the given criteria:
- Continent's name: starts from 'A' or has 'rica' BUT exclude 'Africa'.
- Has a per-capita income of more than 10000 OR is not landlocked.
Let's do that using normal model methods.
countries = (( Country.objects.filter(continent__name__istartswith="A") | Country.objects.filter(continent__name__icontains="rica") ).exclude(continent__name__iexact="Africa")) & ( Country.objects.filter(pci__gt=10000) | Country.objects.filter(is_landlocked=False) )
We have already been really overwhelmed by the complexity of this query. Let's use
Q and see its magic.
from django.db.models import Q countries = Country.objects.filter( ( Q(continent__name__istartswith="A") | Q(continent__name__icontains="rica") & ~Q(continent__name__iexact="Africa") ) & ( Q(pci__gt=10000) | Q(is_landlocked=False) ) )
As we can see, using
Q objects has the potential of refactoring a lot of complex code and making it more readable.
Thank you for your time. To know more about
Q object, visit Django Docs
Happy Reading, Keep Pythoning