Welcome to this lesson, great to have you on board. My name is Henry and I am excited to continue with this tutorial series where we are building blog application using Django 1.11.4 and Python 3.5. We are in our sixth lesson, working with queryset and managers for our blog Post model. In the previous lesson, we learned how to customize Django admin site by editing admin.py file.
In this lesson, we will first learn how to create, update, retrieve and delete objects in the database. We will then see how we can create model managers. Now that you have a fully functional administration site to manage your blog content, it’s time to learn how to retrieve information from the database and interact with it.
Django comes with powerful database abstraction api that let’s you create, retrieve, update and delete object easily. The Django Object Relation Mapper (ORM) is compatible with database like Mysql, Sqlite, Postgresql and Oracle. Remember that you can defined the database of your project by editing database settings in the settings.py file of your project. Django can work with a multiple database at a time and you can even program database routers that handle data in any way you like. Once you have created your data models, Django gives you a free api to interact with them. Now let’s create objects.
To create your first object, activate your virtual environment and navigate to your project base directory where manage.py file is located on your terminal. Run the following command to open the python shell: python manage.py shell Here is a screen-shot of my python shell:
The three greater than symbol shows that our python interactive console is ready for input. First, we need to import the library, enter the following command: from django.contrib.auth.models import User and hit enter. Enter the following command: from blog.models import Post and hit enter. What I want to do now is to get a user from my database using the python interactive console, enter the following command: user = User.objects.get(username=’henry’) and hit enter. Note: You must enter an existing username in the database, otherwise you will get an error. To create a post, enter the following command: post = Post.objects.create(title=’Django Blog App’,slug=’django-blog-app’, body=’learning how to create blog’,author=user) Here is a screen-shot of my terminal showing how this commands were executed:
Let’s analyze what we have done:
from django.contrib.auth.models import User – Here we import the User model from our authentication framework.
from blog.models import Post – We are importing Post model from our blog app.
user = User.objects.get(username=’henry’) – We retrieve the user object that has the username henry. The get method allows you to get a single object from the database. Note that this method expects a single result that matches the query.
post = Post.objects.create(title=’Django Blog App’,slug=’django-blog-app’, body=’learning how to create blog’,author=user) – We are creating a post instance with a custom title, body, slug and we set the user(henry) whom we retrieved, as the author of the post.
The post object we created is in computer memory and is not persisted to the database. To save the post object, we need to use the save method, run the following command: post.save() Here is screen-shot of my terminal showing the save method:
The post.save() command performs insert SQL statement behind the scene.
Retrieving Object in Our Interactive Console
The Django Object Relation Mapper (ORM) is based on queryset. A queryset is a collection of objects in your database that can have several filters to limit the results. You already know how to retrieve a single object from the database using the get method. Each Django model has at least one manager and the default manager is called objects.
To retrieve all our blog post from the database we can use the all method, run the following command: post_query = Post.objects.all() This is how we create a queryset that return all objects in the database. Note that post_query = Post.objects.all() has not been executed yet, Django queryset are lazy and they are only evaluated when they are forced to do it. This behavior make Django queryset very efficient, to execute our query; run the following command: Post.objects.all() Here is a screen-shot of my output:
The above image shows that I have three blog post in my QuerySet. Now let’s learn how we can use the filter method. I am going to show an example where we filter post created by the author henry. To execute this, I will run the following command: Post.objects.filter(author__username=’henry’) and lastly I will show how to filter using multiple fields. For example, I want to get all post written by henry in the year 2017. This is the command I will use: Post.objects.filter(publish__year=2017, author__username=’henry’) Here is a screen-shot of my terminal:
We are building queries with field lookup method using two underscores e.g author__username. The next thing we need to learn is the exclude method, you can exclude certain result from your queryset using the exclude method of the manager. For example, we can retrieve all post published in 2017 and whose title doesn’t start by the word Django. We can use this command: Post.objects.filter(publish__year=2017)\ after typing backslash hit enter and type .exclude(title__startswith=’Django’) this is called chaining filters in a queryset. Here is a screen-shot of my terminal:
We will now use the order_by method, you can order your result by different fields using the order_by method of the manager. For example your could retrieve all objects ordered by their title. To do this, run the following command: Post.objects.order_by(‘title’)
If you want to delete an object, you can do it from the object instance by passing an id using this command: post_del = Post.objects.get(id=1) and then calling the delete method using the following command: post_del.delete() Here is a screen-shot of my terminal:
So what happens when queryset are evaluated. You can concatenate as many filters as you like, to a QuerySet and you will not hit the database until the queryset is evaluated. To learn more about queryset visit Django QuerySet.
As we previously mentioned, objects are the default manager of every model which is used to retrieve all objects in the database, but we can also defined custom managers for our models. We are going to create a custom manager to retrieve all post with their published status. There are two ways to add managers to your models, you add extra manager methods or modify initial manager queryset.
Edit the models.py file of our blog application and make sure it has the following code.
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
# Custom Manager
# Our Post Model
STATUS_CHOICES = (
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date='publish')
author = models.ForeignKey(User, related_name='blog_posts')
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
# The default manager
objects = models.Manager()
# Custom made manager
published = PublishedManager()
ordering = ('-publish',)
From line 7 – 9, we defined our custom manager for our Post model. On line 8, we have get_queryset method that returns queryset to be executed. After defining our custom manager, we need to use it in our Post model to perform queries, to do this we call this manager on line 32. To learn more on custom managers visit Django Database Managers.
Goals achieved in this lesson
We learned how to launch python shell.
We learned how to import models in our python shell.
We learned how to retrieve and delete objects in our python shell.
We learned how to create custom manager for retrieving our objects.