The Django database-abstraction API provides a rich set of objects and functions that allow you to perform complex queries on the database. We touched on this earlier in this hour when we discussed the all() and get() functions. This section discusses how to use the filter() and exclude() functions to retrieve QuerySets from the database.
The filter(**kwargs) function accepts any number of lookup parameters to use when querying the database. The lookups are field-based. Only entries whose fields match those in the lookups are returned in the QuerySet. For example, the following code snippet shows using one filter to query for Blog objects by the name field and another filter to query for Blog objects by the name and text fields:
from iFriends.People.models import Blog blogs = Blog.objects.filter(title='MyBlog') blogs = Blog.objects.filter(title='MyBlog', text='Some Text')
The exclude(**kwargs) function accepts any number of lookup parameters to use when querying the database. The lookups are field-based. All entries whose fields do not match those in the lookups are returned in the QuerySet. For example, the following code snippet shows using one filter to query for Blog objects by the name field and another filter to query for Blog objects by the name and text fields:
from iFriends.People.models import Blog blogs = Blog.objects.exclude(title='MyBlog') blogs = Blog.objects.exclude(title='MyBlog', text='Some Text')
So far, we have done only simple field lookups that look for exact matches using the syntax field=value. However, the database-abstraction API provides numerous types of field lookups that allow you to create complex queries.
These field lookup types are applied by attaching them to the end of the field name using a double underscore. For example, the following line of code performs a query using the iexact field lookup type on the title field of the Blog object:
blogs = Blog.objects.filter(title__iexact='MyBlog')
The information in the field lookup is translated behind the scenes into an SQL query by the Django database-abstraction layer so that the database can be queried. For instance, in the preceding example, the case-insensitive iexact search would be translated into the following SQL statement:
SELECT ... WHERE title ILIKE 'MyBlog';
The following is a list of the different types of field lookups that you can use in filter(), exclude(), and get() functions:
exact finds an exact match. This is the default if no lookup type is specified:
blogs = Blog.objects.filter(name__exact='MyBlog')
By the Way
If you specify None as the value for the exact lookup type, it is translated into NULL for the SQL query. This is a good way to find entries that have NULL field values.
iexact finds a case-insensitive exact match:
blogs = Blog.objects.filter(title__iexact='myblog')
contains finds entries that contain the specified text:
blogs = Blog.objects.filter(title__contains='Blog')
icontains finds entries that contain the specified case-insensitive text:
blogs = Blog.objects.filter(title__icontains='blog')
search is similar to the contains lookup type, except that it takes advantage of the full-text search available in MySQL.
You must configure MySQL to add the full-text index before you can use the search lookup type. Also, this is currently available only on MySQL, so you may not want to use it if you plan to port the site to another database engine.
gt finds entries that are greater than the specified value:
blogs = Blog.objects.filter(id__gt=9)
gte finds entries that are greater than or equal to the specified value:
blogs = Blog.objects.filter(id__gte=10)
lt finds entries that are less than the specified value:
blogs = Blog.objects.filter(id__lt=10)
lte finds entries that are less than or equal to the specified value:
blogs = Blog.objects.filter(id__lte=9)
in finds entries that are contained in the specified set:
blogs = Blog.objects.filter(id__in=[2,4,6,8])
startswith finds entries that start with the specified string:
blogs = Blog.objects.filter(title__startswith='Test')
istartswith finds entries that start with the specified case-insensitive string:
blogs = Blog.objects.filter(title__istartswith='test')
endswith finds entries that end with the specified string:
blogs = Blog.objects.filter(title__endswith='Test')
iendswith finds entries that end with the specified case-insensitive string:
blogs = Blog.objects.filter(title__iendswith='test')
range finds entries whose values fall inclusively between a list of two specified values:
dateA = datetime.date(2000, 1, 1) dateB = datetime.datetime.now() blogs = Blog.objects.filter(postDate__range=(dateA, dateB))
year finds date entries whose year value matches the specified year:
blogs = Blog.objects.filter(postDate__year=2008)
month finds date entries whose month value matches the specified month:
blogs = Blog.objects.filter(postDate__month=12)
day finds date entries whose day value matches the specified day:
blogs = Blog.objects.filter(postDate__day=24)
ISNULL accepts either True or False as the value and then finds entries that are either NULL or not NULL, respectively:
blogs = Blog.objects.filter(text__ISNULL=True)
regex accepts a regular expression statement for the SQL backend and then uses that expression in the SQL query:
blogs = Blog.objects.filter(title__regex=r'^(An?|The) +')
iregex accepts a regular expression statement for the SQL backend and then uses that expression in the case-insensitive SQL query:
blogs = Blog.objects.filter(title__iregex=r'^(An?|The) +')
Now it's time to put together all the pieces we have discussed in this section. The all(), get(), filter(), and exclude() functions are all part of the QuerySet class of objects that is attached to each object in the model. The all(), filter(), and exclude() functions all return QuerySet objects. You can also use the all(), get(), filter(), and exclude() functions on each new QuerySet object that is returned. For example, consider the following code snippet:
qs1 = Blog.objects.filter(title__icontains='test') testBlogs = qs1.exclude(postDate__year=2008)
The first QuerySet object, qs1, contains all Blog entries whose title field contains the text test. The second QuerySet object, testBlogs, refines the initial QuerySet to exclude any Blog entries posted in the year 2008. By joining the QuerySets in this manner, you can create complex lookups in your code to handle the most complex types of database queries.
Django also provides another object, django.db.models.Q, that helps immensely with difficult queries. The Q object allows you to encapsulate a collection of field lookup arguments. For example, the following code snippet encapsulates a contains field lookup in a Q object and assigns it to variable q1:
from django.db.models import Q q1 = Q(title__contains='test')
The filter(), exclude(), and get() functions accept the Q objects as their arguments. You can also use the | and & operators to define SQL OR and AND behavior in the queries. For example, the following code snippet shows how to define two Q objects and then use them with OR and AND logic in the filter() function:
from django.db.models import Q q1 = Q(title__contains='test') q2 = Q(title__contains='obsolete') oldBlogs = Blog.objects.filter(q1 | q2) oldTestBlogs = Blog.objects.filter(q1 & q2)
To illustrate this further, let's look at a slightly more complex query that involves using Q objects and QuerySets:
from django.db.models import Q qs1 = Blog.objects.filter(uName__exact='Admin') qs2 = qs1.exclude(postDate__year=2008) q1 = Q(title__contains='SPAM') q2 = Q(title__contains='obsolete') oldBlogs = qs2.filter(q1 | q2 )
Another valuable function that is available through QuerySet objects is the order_by() function. The order_by() function accepts one or more field names as its arguments and then returns a new QuerySet that is ordered based on the field name you specify.
For example, the following code creates two QuerySets, qs1 and qs2. qs1 is ordered by the title, and qs2 is ordered by the postDate:
qs1 = Blog.objects.all().orderby('title') qs2 = Blog.objects.all().orderby('postDate')
Watch Out!
Django does not have case sensitivity built into the order_by() function. Therefore, the order is determined by the database backend.
Django orders the list by default in ascending order. You can also order the objects in descending order by specifying a – before the field name:
qs1 = Blog.objects.all().orderby('-postDate')
Did you Know?
Django provides a handy tool to randomize QuerySets. If you specify a ? as the only argument to order_by(), as in the following code, order_by() returns a randomly ordered QuerySet.
qs1 = Blog.objects.all().orderby('?')
Try It Yourself: Perform Queries on the DatabaseIn this section, you will use the Django shell to add some Blog entries to the database. Then you will perform queries on them to get a feel for how the queries work and how to include them in your code later. Follow these steps from the Django shell to create some Blog entries, and then perform queries on them:
|