Logo Passei Direto
Buscar

Illustrated Guide To Django

User badge image
MMM

em

Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

LEARN DJANGO
By Building a Blog application
By
A BEGINNER ILLUSTRATED GUIDE
WINSTON JC MHANGO
TABLE OF CONTENTS
Why this Booklet and what is in the remaining parts?
The HTTP Protocol and the web
Introduction to Django
Installing Django and understanding its Structure
The Django Blog Application Project Detail List
Creating the Django Blog Application
Blog App package files
Registering the blog app to the project
Creating blog Post Model
Adding Blog Post Model to Admin site
Creating blog posts list and detail views
Adding and configuring the blog app urls
Creating blog posts list and detail templates
01
02
03
04
05
06
07
08
09
10
11
12
13
TABLE OF CONTENTS
Creating blog posts pagination feature
Adding a Tagging Feature to posts
Adding a Featured Image to the post
Creating Related Posts Feature to the blog
Adding a Comments Feature to the blog post
Creating a Recent Posts feature to the Blog app
Creating User Authentication system
Creatiing the Most Popular Author Feature
Creating Categories Feature 
Creating REST API with Django
Using Django Rest Framework
Setting up DRF
Creating Serializers
14
15
16
17
18
19
20
21
22
23
24
25
26
TABLE OF CONTENTS
DRF Views and Class Based Views
DRF Routes and Authentication
Introduction to React 
Consuming a Django Rest Back end with React
Hosting a React app with Netlify
Introduction to Next .JS
Creating a Next.JS App
Consuming Django Rest Back end with Next.JS
Deploying a Next.JS Application 
Introduction to React Native
Creating an Android app with React Native
Consuming a Django Rest API with React Native
27
28
29
30
31
32
33
34
35
36
37
38
1. WHY THIS BOOKLET ?
An Illustrated guide to help beginners!
When I started programming,my goal was to build android 
applications,and so I learnt Java. But through some research and taking a 
few online courses I noticed the trend in web development jobs and 
career prospects being on the higher side as compared to my primary 
choice. I jumped to learning python because of the applications like 
instagram,pinterest,likedIn and others that had been built with 
frameworks based on this language.
Many of them had been developed with Django. But when I started 
learning Django, I got frustrated and ,honestly, it felt like it was a 
framework for people with super brains! I could’nt easily grasp what 
those files and intimidating structures really were and how they 
worked together. There wasn’t a single resource that helped my poor 
novice(beginner) brain quickly draw mental illustrations and quickly 
put things together. 
I went down to start a minimal, flask,framework that only required a 
seven lines script to get beautiful Python language I had grown to love, 
to print something to the web page. But I always knew I needed Django.
This booklet is the guide I wish existed when I first attempted to 
learn web development with Python using Django. There is no doubt 
that Django has the best documentation. But without doubt , there 
are a lot of beginners like I was that find figuring out and drawing 
mental illustrations of how django works so difficult. 
My goal with this booklet is to fill in the gaps and use visual illustrations 
to showcase how beginner-friendly and what a perfect solution Django 
framework really can be.
1. 1 WHAT IS IN PART2 , AND PART 3 OF THIS 
DJANGO BOOKLETS SERIES?
ADVANCED WEB DEVELOPMENT CONCEPTS FOR REAL WORLD PRODUCTION PROJECTS
In this first part of the booklet series, we will cover the 
basics of Django web framework. This will teach you 
enough concepts for building dynamic web apps. You can 
model and develop complex apps with even more 
features that come built in with Django with this 
knowledge.
But the internet and modern apps follow the decoupled 
design patterns, where the back-end and front-end are 
separate codebases, with each served from different/same 
hosts. These design and development decisions solve 
certain programming challenges that are meant to improve 
user experiences(SEO, app speeds) and programming 
experiences(code reuse).
To implement these ,we need to decouple our Django
applications by extending it with either JavasScript or front-
end frameworks like React, React Native,Flutter, Vue, Svelt
and others. 
Eventually our Django back-end needs to operate as an API 
end points, simply relaying data between databases and 
front-end apps. The easiest way to accomplish this is by 
extending our Django framework with Django Rest 
Framework and others.
In the remaining Chapters we will see how to implement this 
by Creating a REST API for the blog app and the features we 
created in it. We will consume these API end points with a 
React web front end , a Next.JS front end and finally a React 
Native Android app. 
Well, if you already know the basics, and probably have 
some projects with it, you can go ahead and GET AN 
ILLUSTRATED GUIDE FOR DECOUPLED DJANGO APPS
https://marvelous-founder-1838.ck.page/1aefcf35eb
1. 1 DOWNLOADING THE CODE FOR THIS BOOK
Be kind and give some star to the project!
If you wish to see the complete project and run it, GET IT 
FROM THIS REPOSITORY ON MY GITHUB JUST MAKE 
SURE YOU GIVE IT A START, ITS BOOST , I WILL LOVE TO 
SEE THIS PROJECT STARED. AND WHO KNOWS, EVEN 
MORE BEAULTIFUL FEATURES MIGHT GET ADDED.
AND THATNKS IN ADVANCE FOR THE STARS YOU LEAVE 
THERE.
BROWSE MY BLOG FOR RELATED CONTENT AND TIME TO 
TIME UPDATES AT WWW.CODESNNIPPETS.COM
https://github.com/winstonmhango23/Illustrated-Guide-to-Django-part-one
http://www.codesnnippets.com/
2.1 THE HTTP PROTOCOL AND THE WEB
How does the web work?
Before we can start building our web applications or 
even learning the django web framework,it is very 
important that we get hold of how the web works. The 
web operates on top of the well established internet 
structure. By definition,the ineternet is a network of 
networks.
The internet has existed since the 1960s. Around 1980s it 
was first used by governments,military and some research 
institutions. In 1989, Berners-lee,who worked at CERN, 
inverted the HTTP. His insight was that the existing 
hypertext system, where text displayed on a computer 
screen containing links to other documents ,could be 
moved onto the internet. The invention of Hypertext 
Transfer Protocol (HTTP) was the first standard, universal 
way to share documents over the internet. 
The HTTP is one of protocols of the application layer of 
the 4 internet protocols layers(TCP/IP model) and is used 
to share html documents over the internet.
2.1 THE HTTP PROTOCOL AND THE WEB
How does the web work?
The HTTP works around the client-server architecture. 
The client sends requests and the server sends back 
responses. The server stores resources(html pages, 
data…) which are located and requested by the client in 
form of URLs.
The request/response cycle is based around the HTTP 
action verbs/methods which determine what happens to 
the requested resources. The GET verb is used to get the 
resources from the server, the POST is used to Create 
resources, PUT updates, while DELETE, simply deletes.
2.2 DJANGO AND THE HTTP PROTOCOL
How does the web work?
Django uses the httprequest and httpresponse objects to 
handle web requests and responses. 
Just like any other web framework, Django aims at 
making web development an easy task. It is very tough to 
create the routine for channeling the client requests and 
responses while binding data contexts to our responses 
from scratch. As we will see in the coming chapters, 
Django abstracts all that low level programming tasks 
for us by using Python’s built-in libraries like http, 
requests and others. For us, all we need is simply to 
import these classes and call the relevant methods from 
them to use the http requests and responses.
3. INTRODUCTION TO DJANGO
What is Django and why learn it?
Why Django? Well you don’t need to dig the internet hole 
to get inspired and considerNone as default value. 
This parameter will be used in the URL.
 Build the initial QuerySet, retrieving all published posts, and if there is a 
given tag slug, we get the Tag object with the given slug using the 
get_object_or_404() shortcut.
 Filters the list of posts by the ones that contain the given tag. Since this is 
a many-to-many relationship, we have to filter by tags contained in a 
given list, which, in our case, contains only one element.
Next we need to add a url pattern to the urls.py for our blog 
application.This pattern will be used to match to the post_list view by a 
specific tag slug.
15.4 Filtering posts by tags
2
3
15. Adding a tagging feature to posts
Open our urls.py in the blog application and add the pattern below.
urlpatterns = [
path(‘ ', views.post_list, name='post_list'),
path('tag//',views.post_list,name='post_list_by_tag'),
path('////',views.post_de
tail,name='post_detail'),
]
We have added the second pattern which will call the view with the tag_slug
parameter. To access tags in the template, add the following lines above the 
{% for %} loop as below:
{% if tag %}
All posts tagged 
"{{ tag.name }}“ 
{% endif %}
If a user clicks on a tag, they will see the tag that they are filtering by 
preceded with the text “All posts tagged”, and then the name of the tag. 
Below is how we will display all the posts tagged with the selected tag.
{% for tag in post.tags.all %}
 {{ tag.name }} 
{% if not forloop.last %}, {% endif %}
{% endfor %}
15.4 Filtering posts by tags
2
3
15. Adding a tagging feature to posts
If we click on a tag,you should be able to see results displayed as in the 
screenshot below.
As a way of appreciating whatever we have covered, open the detail.html 
template and modify the code for displaying posts by tags like in the list.html 
above.
15.4 Filtering posts by tags
2
3
6
16. Adding a featured image feature
A featured image is one of the best user experience 
enhancement features for a content driven dynamic web 
application. A featured image helps to give the reader a 
quick mental picture of what the content is all about. Above 
all,according to research, posts with images will rank high 
on search engines ,and have more views than those that 
don’t. 
In this chapter,we will take a look at how to create a 
featured image feature for our blog application.
In Django, files which are uploaded by the user ,such as pdf,doc,images,etc
,are called Media Files. 
Just as with static files, to serve media files we have to add some configurations in our settings.py file
16.1 Introduction
2
3
6
16. Adding a featured image feature
These are actually files and they need to be stored and accessed somewhere. 
The uploaded files are not stored in the database but in the filesystem. To 
upload any media,the model we want to have an attribute/column with that 
media needs to have a proper modelfield type.
For this, Django has FileField and ImageField types. So if we need to add a 
featured-image field to our Post model,we need to modify it and add the 
ImageField as below.
That in itself is not enough, we need to add configurations to our stings.py
module in our main project to indicate where the media files should be saved 
and accessed. 
Before getting anywhere,we need to run our database migration and migrate 
the models to reflect new modelfield changes.
Run python manage.py makemigrations
Run python manage.py migrate
Up next,open the settings.py module of our main project. Add the two 
lines below to it.
class Post(models.Model): 
#.......
featured_image = 
models.ImageField(upload_to='featured_image/%Y/%m/%d/') 
Here we assign the model.ImageField to featured_image variable, as a 
field(column). The upload_to parameter indicates the filefolder where the 
files will be automatically uploaded to.
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
16.2 Iclude the FileField type to our Post model
2
3
6
16. Adding a featured image feature
If we go ahead and create a post using our admin site,we will see a 
featured_image field added to the attributes of our post as seen in the 
sceenshot below.
As it is, we cannot access these media files in our templares. The problem is 
that Django development server doesn't serve media files by default. To make 
Django development server serve static we have to add a URL pattern in 
sitewide urls.py file as below.
16.3 Serving media files to templates
2
3
6
16. Adding a featured image feature
Now the next part is to render the featured_image to the templates. Open the 
list.html template of our blog application and add the code below just on top 
of the blog title
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls', namespace='blog')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
Below is the complete code for displaying a post in our list.html template with 
a featured image included. Underneath it is its screenshot. You should 
download the full code for the whole tutorial to get a detailed templates code.
16.3 Serving media files to templates
2
3
6
16. Adding a featured image feature
Now the next part is to render the featured_image to the templates. Open the 
list.html template of our blog application and add the code below just on top 
of the blog title
{% for post in posts %}
 
{{ 
post.title }} 
{% for tag in post.tags.all %}
 {{ tag.name }} 
{% if not forloop.last %}, {% endif %}
{% endfor %}
Published {{ post.publish }} by {{ post.author }}
{{ 
post.body|truncatewords:30|linebreaks }}
{% endfor %}
Below is the screenshot of the results of the code above.
16.3 Serving media files to templates
2
3
6
16. Adding a featured image feature
There is quite a bit to cover on how to post and process images and files 
especially how to upload using a form. We will cover that in the user profiles 
topic. For now,I hope this gives us an idea of how easy it is to work with 
django files and images.
16.3 Serving media files to templates
2
3
6
17. Adding related posts feature
A related posts is another user experience enhancement 
feature for content centered applications. As the name 
suggests, related, or say similar, is a feature that is used to 
display a list of items,posts,blogs, that are having some kind 
of similarity to the currently displayed item/post. The 
relationship is completely based on the queryset used. It 
could be category based , tag based , phrase based , title 
based and etc.
In this chapter , we will learn how to create a related posts 
feature for our blog application. We will have our related 
posts displayin a grid like in screenshot below.
We will build a functionality to display similar posts by tags they share. In this 
way, when a user reads a post, we can suggest to them that they read other 
related posts.
All the modifications required to implement the related/similar posts 
feature will be done on our post_detail view.
17.1 Introduction
2
3
6
17. Adding related posts feature
 Retrieve all tags for the current post
 Get all posts that are tagged with any of those tags
 Exclude the current post from that list to avoid recommending the same post
 Order the results by the number of tags shared with the current post
 In case of two or more posts with the same number of tags , recommend the 
most recent post
 Limit the query to the number of posts we want to recommend
from django.db.models import Count
#.........
post_tags_ids = post.tags.values_list('id', flat=True)
similar_posts = Post.published.filter(tags__in =post_tags_ids). 
exclude(id=post.id)
similar_posts = similar_posts.annotate(same_tags=Count('tags')) 
.order_by('-same_tags','-publish')[:3]
Our similar posts will be extracted based on shared tags. If a post has tags 
similar to those of another post , they will be considered similar/related. 
In order to accomplish this, we will follow steps listed below.
These steps describe what QuerySet we will write to get our related posts.
Open the views.py file of our blog application and add the following code just 
before the render function.
17.2 Query Design algorithm
2
3
6
17. Adding related posts feature
return render(request, 'blog/post/detail.html', {'post': post, 
'similar_posts‘ : similar_posts})
The code above works as follows:
 We retrieve a list of IDs for the tags of the current post. The values_list() 
QuerySet returns tuples with the values for the given fields. The flat=True
generates a flat list like [1, 2, 3, ..].
 Gets all posts that contain any of these tags, excluding the current post 
 The Count aggregation function imported at the top is used to generate a 
calculated field —same_tags— that contains the number of tags shared 
with all the tags queried.
 Finally,we order the result by the number of shared tags (descending 
order) and date published to display recent posts first for the posts with the 
same number of shared tags. We slice the result to retrieve only the first 
three posts.
Lastly we need to add the similar_posts object to the context dictionary for 
the render() function, as shown below:
To display our related posts in the template, edit the blog/post/detail.html 
template and add the following code at the bottom, just before the 
{endblock}.
17.2 Query Design algorithm
2
3
6
17. Adding related posts feature
 
 
Related Posts
{% for post in similar_posts %}
{{ post.title }} 
{% empty %}
There are no posts related to this one yet.
We are using the for loop to iterate through our similar_posts QuerySet 
object to retrieve all the posts with properties specified in the query. Our 
template displays the post featured_image and title. The empty tag at the 
bottom is used to display a string under it if there are no posts related to the 
current. 
Open the console and run python manage.py runserver to start the 
development server. Click at any of the posts to display it. Below is the 
screenshot of the results for related posts.
17.3 The html template
2
3
17. Adding related posts feature
Be sure to download the code for the complete project to check for 
reference if anything doesn’t work with your code.
Open the console and run python manage.py runserver to start the 
development server. Click at any of the posts to display it. Below is the 
screenshot of the results for related posts.
17.3 The html template
2
3
6
18. Adding a comments feature to the blog
A comments feature is one of the most important 
components of content driven dynamic web applications. 
The reasoning behind this feature is encourage feed back 
and boost engagement with site users. 
In this chapter , we will learn how to create a comments 
feature for our blog application. Here is how we want our 
comments to be presented..
All the modifications required to implement the comments feature will be 
done on our post_detail view.
18.1 Introduction
2
3
6
18. Adding a comments feature to the blog
In this chapter, among other things, we will learn how to use forms in django. 
The forms will be used to submit comments to the related post. But first things 
first, a comment system will be used to store data(comments) into the 
database. We therefore need to create a model to capture and store the 
comments. 
Open the model.py of our blog application and add the code below to it.
The model contains ForeignKey field to associate the comment with a single 
post. This is a many-to-one relationship defined in the Comment model 
because each comment will be made on one post, and each post may have 
multiple comments. 
class Comment(models.Model):
post = models.ForeignKey( Post, on_delete= models.CASCADE, 
related_name='comments')
name = models.CharField( max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField( auto_now_add=True)
updated = models.DateTimeField( auto_now=True)
active = models.BooleanField( default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comment by {} on {}'.format (self.name, self.post)
18.2 Creating a comments model
2
3
6
18. Adding a comments feature to the blog
The related_name field will allow us to name the attribute that we use for the 
relation from the related object back to this one. If we don't define the 
related_name attribute, Django will use the name of the model in lowercase, 
followed by _set (that is, comment_set) to name the manager of the related 
object back to this one.
To make sure not allcomments are automatically displayed to other readers, 
we included an active boolean field that we will use to manually approve or 
disapprove comments. The created field is used to sort comments in a 
chronological order by default.
Now run python manage.py makemigrations to create database 
migrations for the comments model.
(venv)C:\Users\winst\OneDrive\Desktop\django_blog\mysite>pytho
n manage.py makemigrations
Migrations for 'blog':
blog\migrations\0005_comment.py
- Create model Comment
Then run python manage.py migrate
(venv)C:\Users\winst\OneDrive\Desktop\django_blog\mysite>pytho
n manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions, 
taggit
Running migrations:
Applying blog.0005_comment... OK
This creates a blog_comment table in our
18.2 Creating a comments model
2
3
6
18. Adding a comments feature to the blog
Now that we have the comment model in our database,we need to add it to 
the administration site in order to manage comments through a simple 
interface. 
Open the admin.py file of our blog application, import the Comment 
model, and add the following code to it
from .models import Post, Comment
#......
@admin.register (Comment)
class CommentAdmin (admin.ModelAdmin):
list_display = ('name', 'email', 'post', 'created', 'active')
list_filter = ('active', 'created', 'updated')
search_fields = ('name', 'email', 'body')
Now run python manage.py runserverto start the development server. 
Open web browser and navigate to http://localhost:8000/admin/ . Our 
comments model is added just under the BLOG section as seen below.
18.3 Registering the comments model to admin site
http://localhost:8000/admin/
2
3
6
18. Adding a comments feature to the blog
Forms are one of the fundamental building blocks of any dynamic application. 
Also , they are the most complicated and involving feature of web apps to 
implement. Forms are one of the evil doors to our data security as any input to 
our application from untrusted users is a potential attack. For this, rigorous 
and careful implementation must be a primary consideration to close this evil 
door. Out of the box , Django implements forms API which is easy and safe 
for developers to use.
To create a form from a model, we need to indicate which model to use in 
the Meta class of the form. Django checks the model and builds the form 
dynamically. Each model field type has a corresponding default form field 
type. 
The definition of our model fields determines the form validation. Django 
builds a form field for each field contained in the model by default, but we can 
explicitly name which fields we want to include in our form using a fields list. 
For our CommentForm form, we will use the name, email, and body fields 
because our users will need only these to submit a comment.
We need a form to allow our users to add comments to posts on our site. By 
default , Django has classes for creating forms, the Form and ModelForm 
classes.
In this section we will use the ModelForm to create our form from the 
comment model. Basically ModelForm allow us to create forms from a 
predefined model. 
A little bit of how really Django builds forms is imperative before we can go 
ahead and push on you code that will look gibberish.
18.4 Creating forms for adding comments
2
3
6
18. Adding a comments feature to the blog
When displaying the form in the html templates, we often, including the 
official docs, see the format below:
Using the Django template engine we can get hold of the various attributes of 
the form elements like below.
 
{% csrf_token %}
{{ form }} 
Submit
The {{ form }} template tag works like a magic box , it may contain any 
number of input fields. This tag is so limiting if you want to style the form. 
What Django does is display form fields as:
 as_table()
 as_ul()
 as_p()
Which is table rows, as unordered list and paragraphs. If we run and 
display this code in our html, surprisingly, it does not look like a or 
 elements. To produce that structure , we have to wrap the code in the 
respective html element tags. Below is how we might display it to look like a 
table:
{% csrf_token %}
 
{{ form }} 
 
 Submit 
18.5 How forms work in Django
https://github.com/django/django/blob/1.11.4/django/forms/forms.py#L278
https://github.com/django/django/blob/1.11.4/django/forms/forms.py#L287
https://github.com/django/django/blob/1.11.4/django/forms/forms.py#L296
2
3
6
18. Adding a comments feature to the blog
When displaying the form in the html templates, we often, including the 
official docs, see the format below:
Now we can see how easy it is for us to control and take charge of the design 
decision on how our user interface can be. We can as easily replace the table 
and its table row attributes with unordered list with its list element attributes, 
or just with paragraph elements. 
If you are a Bootstrap, Tailwind css , or any of the mainstream css frameworks 
, you could as easily add these frameworks component or utility class 
attributes to style this form.
 
 
{{ form.name.label_tag }} 
 {{ form.name }} 
 
 
{{ form.email.label_tag }} 
 {{ form.email }} 
 
 
{{ form. body.label_tag }} 
 {{ form. body }} 
 
 
Submit
18.5 How forms work in Django
2
3
6
18. Adding a comments feature to the blog
We can as well target the form’s field of each element, like say, ,.These are normal form input fields and in 
Django , they are called widgets. Widgets are small html templates used to 
generate the output of these fields.
Open the venv/Lib/site-packages/django/forms/ jinja2/django/forms/ 
widgets/input.html of our project in the text editor. This is just one of the 
templates from the widgets folder and it looks like the code below:
Basically this small template sets the input type, it’s name which is used to 
access the data in the request object. For example, an input with name 
“message”, if posted to the server, is accessible via request.POST['message']. 
It includes the attrs.html template, which is responsible for setting attributes 
such as maxlength, required, placeholder, style, or any other HTML 
attribute. Below is how the attrs.html looks like:
{% for name, value in widget.attrs.items() %}
{% if value is not sameas False %} {{ name }}
{% if value is not sameas True %}="{{ value }}“
{% endif %}
{% endif %}
{% endfor %}
18.6 Using Template widgets
https://github.com/django/django/blob/1.11.4/django/forms/templates/django/forms/widgets/attrs.html
2
3
6
18. Adding a comments feature to the blog
There are some cases that you only want to add an extra HTML attribute, like 
a class, a style, or a placeholder. You don’t need to expand the input field like 
in the previous section. You can do it directly in the form definition like 
below:
// forms.py
*/the commentForm form
class CommentForm (forms.Form): 
name = forms.CharField( max_length=30, 
*/using widgets to craft our custom attrs(style and 
placeholder
widget= forms.TextInput( attrs={ 'style': 'border-color: 
orange;', 'placeholder': 'Write your name here' } ) ) 
email = forms.EmailField( max_length=254, 
*/using widgets to craft our custom attrs(style and 
placeholder
widget=forms.EmailInput( attrs={'style': 'border-color: 
orange;'}) ) 
body = forms.CharField( max_length=2000, 
*/using widgets to craft our custom attrs(style and 
help_text
widget=forms.Textarea( attrs={'style': 'border-color: 
orange;'}), 
help_text='Write here your comment here!' )
Since we already have a model,we will have to use modelform and craft our 
custom html attributes using our preferred css framework , tailwind css, to 
create the comment form for our posts. Below is the complete code for our 
commentForm form using tailwind css for the class custom attributes.
18.7 Using custom html attributes
2
3
6
18. Adding a comments feature to the blog
class CommentForm (ModelForm):
class Meta:
model = Comment
fields = ('name','email', 'body')
widgets = {
'name': TextInput(attrs={
'class': "w-full px-3 py-2 pt-5 pb-2 border border-gray-200 
rounded appearance-none input focus focus:border-indigo-600 
focus:outline-none active:outline-none active:border-indigo-600",
'placeholder': 'Name'
}),
'email': EmailInput(attrs={
'class': "w-full px-3 py-3 pt-5 pb-2 border border-gray-200 
rounded appearance-none input focus focus:border-indigo-600 
focus:outline-none active:outline-none active:border-indigo-600", 
'placeholder': 'Email'
}),
'body': Textarea(attrs={
'class': "w-full px-4 py-3 mb-4 border border-2 border-
transparent border-gray-200 rounded-lg focus:ring focus:ring-blue-
500 focus:outline-none", 
'placeholder': 'Write your comment here'
})
}
Using custom css attributes to create a commentForm form with tailwind css 
utility classes.
18.7 Using custom html attributes(adding tailwind css)
2
3
6
18. Adding a comments featureto the blog
The code above is in the form.py of our blog app. To get this form rendered in 
our post_detail.html template we need to add this code to it.
Just below the 
As seen from above,the whole form is included in our post_detail.html with 
fields to be displayed as paragraphs using the comment_form.as_p object. 
The rest of the code is a design to help position and properly size our form in 
the template.
Write a 
comment
{{ comment_form.as_p }}
{% csrf_token %}
18.8 Adding the form to the post_detail template
2
3
6
18. Adding a comments feature to the blog
Running our project using the python manage.py runserver, and open one of 
the blog posts in our site, below the post body we should see this Beautiful 
comment form displayed as needed.
Now that we are done presenting the comment form to our users, its time we 
handle the data they send to our database. To do that we will have to use the 
post_detail view as described in the next section.
18.8 Adding the form to the post_detail template
2
3
6
18. Adding a comments feature to the blog
Since the comments are used on a single post,we are going to use the 
post_detail view to instantiate the form and process it. Open the vies.py file of 
our blog application , import the Comment model and the CommentForm,
add imports for the Comment model and the CommentForm form, and 
modify the post_detail view to make it look like the following:
def post_detail (request, year, month, day, post):
#.........other code here
# List of active comments for this post
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request,'blog/post/detail.html',{'post': 
post,'similar_posts': similar_posts, 'comments': comments,
'new_comment': new_comment,'comment_form': 
comment_form})
18.9 Handling forms in views
2
3
6
18. Adding a comments feature to the blog
In the post_detail view above,we have displayed comments with a QuerySet 
that retrieved all active comments for this post, as follows:
comments = post.comments.filter(active=True)
The final piece to the comment system is displaying the comments to the users 
once posted to our database. To do that,all we need is modify our 
post_detail.html template to provide code that displays comments in it.
{% for comment in comments %}
Comment {{ forloop.counter }} by {{ comment.name }}
{{ comment.created }}
 
{{ comment.body|linebreaks }}
{% endfor %}
18.10 Displaying comments in the template
2
3
6
18. Adding a comments feature to the blog
In the code above we are using the for---in loop to iterate the comments 
object and then use our tailwind css utility classes to interpolate the accessed 
attributes in our template.
{% for comment in comments %}
Below is how the comments are displayed in the browser.
18.10 Displaying comments in the template
2
3
6
 WHAT TO IMPLEMENT NEXT?
So far , we have covered the basics of Django web 
framework. This is good enough for basic dynamic web 
apps. You can model and develop complex apps with even 
more features that come built in with Django.
But the internet and modern apps follow the decoupled 
nature, where the back-end and front-end are separate 
codebases, with each served from different hosts. These 
design and development decisions solve certain 
programming challenges that are meant to improve user 
experiences(SEO, app speeds) and programming 
experiences(code reuse).
To implement these ,we need to decouple our Django 
applications by extending it with either JavasScript/front-
end frameworks like React, Vue, Svelt and others. 
Eventually our Django back-end needs to operate as an 
API end points. The easiest way to accomplish this is by 
extending our Django framework with Django Rest 
Framework and others.
In the remaining Chapters, covered in part two and three, 
we will see how to implement this by Creating a REST API 
for the blog app and the features we created in it. We will 
consume these API end points with a React web front end 
, a Next.JS front end and finally a React Native Android 
app. 
DOWNLOAD PART TWO(BUILDING DECOUPLED 
DJANGO APPS WITH REACT.JS,NEXT.JS,AND VUE.JS)
Create Modern DECOUPLED ,fast, single page apps, React, Next.js and React 
Native Apps Consuming Django Rest API back ends.
https://marvelous-founder-1838.ck.page/1aefcf35eblearning and start using 
Django. Some of the most popular applications you are 
using are built with Django… Instagram, Pinterest, 
Spotify,Mozilla and National Geographic are just a few 
examples to draw your attention to start using Django.
A web application consists of the front-end and the 
back-end. Django Uses the MVT pattern which makes 
glueing these two worlds together so easily! Django goes 
beyond just pattern implementation. It comes with 
features most common in the web development.
The story of Django starts with Python. Python is one of 
the most popular programming languages. It is used to 
build different types of applications. Python is used for 
building web applications using Django, Flask and other 
frameworks. Among all the python web frameworks, 
Django is the most popular . In this bite-sized and 
concise booklet , we will walk through different features 
of Django by building a Blogging application.
3. INTRODUCTION TO DJANGO
In this guide ,we will get as practical as creating and 
implementing features to the blog application we will be 
using as learning project to show each of the common 
django features.
It goes with a famous quote ”a web framework with 
batteries included”. Django comes with common features 
like registration, authentication, admin site and others in 
the form of pre-built applications. So all you need is install 
and extend or simply use them. 
Unlike other frameworks, Django comes with its Object Relational 
Mapper and templating engine. These features make the process of 
designing and development of dynamic, scalable and maintainable 
web apps a quick and easy process. With the use of its third party 
python libraries, the MVT pattern makes Django the perfect 
framework for developing APIs too.
Why learn Django ?
THE FRONT-END TECHNOLOGIES(GOES IN THE TEMPLATES]
4. INSTALLING DJANGO
Before we can get anywhere, we first need our environments ready. 
The primary requirement for one to take this mini-booklet based 
course is knowledge of Python. Atleast you need to know the basics 
of variables, functions,classes and the general principles of OOP 
concepts, and working with databases in Python.
All that aside,we first need Python to be installed. Download python 
from python.org. 
Click here
Select the package for your operating system and go ahead to 
download it. Click to install it and follow the installation steps that 
are packed right in the python installer for your operating system. 
Once installed type python on the console to verify if python is 
installed properly. You should see the results as shown below.
You need Python First
python.org
4. INSTALLING DJANGO
This is a practical project based booklet. We will therefore explain 
every bit of the concepts we can manage with code. We need to get 
started with preparing working project folders.
Since we have Python installed on our machines, the next logical 
step is to create a Django project folder and its necessary working 
environments.
Create a project folder
Create a project folder on the desktop and name it 
django_blog. Navigate into it using cd django_blog as seen 
below
Create a virtual environment
At its core, the main purpose of Python virtual environments 
is to create an isolated environment for Python projects. Use 
virtualenv venv to create it inside our project folder as shown 
below.
command Created environmrnt folder
comm
and
Created project 
folder
Prepare Django Project Folders!
4. INSTALLING DJANGO
Activate the virtual environment and Create a Django Project
Activate the created virtual environment, the venv folder, 
inside the django_blog. Install Django using pip install django
command. Use django-admin startproject command and 
create a project named mysite. Follow the commands in the 
screenshot below. 
Creating a django project named mysite
Activating the virtual environment
Once installed on your machine,django offers a full set of commands that 
you can use to create and manage projects. The django-admin is a 
command from our django installation. Here it is used to create a django
project. Once you create a project, manag.py is automatically installed in 
each project. At project level,you will have to use the manage.py 
commands, like when we want to run database migrations,create apps, 
create super users, run project server and etc.
Now that we have our project created,the next thing is to run and at least 
get to see the rewards of all that technical run arounds before we can 
continue with routine. Navigate to mysite project we just created with 
your console and enter python manage.py runserver command to start 
the development environment. You should see the lines below in your 
console. Then open your browser and enter http://127.0.0.1:8000/
Create and run the Project 
https://docs.djangoproject.com/en/3.2/ref/django-admin/
4. INSTALLING DJANGO
Let us take a look at the files and the structure of what gets installed 
and created in the django project. This will help us understand how 
each of the files work and overall design pattern of django framework.
Once you navigate to that address you will be greeted with the django
success page below.
The Django Project files and Structure
Django is designed for a developer to 
follow a specific pattern. The initial 
project files give a base structure where 
you plugin your packages,apps,as called in 
django.On the right is a screenshot of the 
mysite project represented as the main 
app in the schematic above, to which 
other apps are attached.
3 4
5 6
Django projects are designed to be large : a single Django 
project is intended to consist of packages, or as Django calls 
them, “apps”.
4. INSTALLING DJANGO
The Django Project Structure(the package/apps)
1 2
3 4
6
One of these apps,the main project, has to share the name of the 
parent project. In our case, mysite. This app contains the “core” of 
our project. It serves as the entry point, which ties our other apps 
together. In this app, there is a settings.py module which holds 
settings such as database information, that are common to all of our 
apps in the project. It would be accurate to state that Django projects 
are a collection of app “nodes,” where mysite(in our case) is our 
“master node.” This main app package contains a few default 
modules which are:
Django is designed around the MVT pattern, which is a sort of an 
MVC pattern. Django is from ground up designed to work by building 
projects as a collection of apps. We will go in details about the MVT 
in the next chapter.
4. INSTALLING DJANGO
Settings.py handles everything related to configuration. Here is 
where we connect other apps to the main app,activate Django plugins, 
store database credentials, set our hostname, etc. You dont want to 
commit to Github this file, if you do, make sure you hide the credentials.
Below is an illustration of how the settings.py binds all the custom apps 
that we will create later to the main project. In the illustration we are 
imagining we have two apps, ablog and members, and we are joining 
them to the main project through the settings module. 
3
__init__.py sets up this folder as a package.When python interpreter 
encounters this folder,it is interpreted as python package. If you gone 
through a python programming course,this is not a new concept.
. 
1
wsgi.py is a standard that defines how applications and servers 
communicate with each other. In a django project it offers an entry-
point for WSGI-compatible web servers to serve your project.
2
Django project structure and concepts
1 2
3
6
4. INSTALLING DJANGO
Later, when we create the blog app, we will get a step further showing 
how the app.py module gets configured to connect back to the main 
project application through the settings.py.
The Django project structure and concepts
1 2
3
6
URLs.py is where we set the top-level URLs for a django project. 
Remember: Django projects are meant to be divided into individualpackages(apps), so this file usually reserves a URL for each package(app), 
with different modules in them handling their own independent URL 
routers.
4
4. INSTALLING DJANGO
The urls.py is also a module that sets the resource location routes for the 
various endpoints. These urls point to various views(we will discuss about 
views later)eg post_list, which connects our apps to different html 
templates(we discuss templates later)
Django Project structure and concepts
1 2
3
5. DJANGO BLOG APPLICATION DETAIL LIST
Django’s magical powers come to life through the creation of 
apps. As indicated in the previous chapter, a django project 
is a collection of Python packages and some settings 
modules. To define our desired project features and 
functionalities, django allows the creation of custom 
packages. These custom packages are what django
calls apps. Besides the custom packages(apps),a 
django project installs its built-in apps. 
In this chapter we will lay down the steps we will follow to 
create a blog application which will help and serve as guide 
to learning the concepts of Django. 
# Creating and configuring the app where we will create the app
App package files where we will identify modules in the app
# Installing(registering) the app to the project where we will 
add the app to our default app(project)
#1
Creating blog urls where we will add urls.py module to the blog 
package and register UrlConfig to the project urls.py
Adding blog Post model to admin site where we will add blog 
posts model to the django built-in admin site
#1
#1
Creating blop post list_view where we will add blog posts view 
functions that will display posts to the user#1
Creating blog Post model where we will add blog posts related 
tables and its attributes(columns)
#1
5.1 The Blog app project Details
2
5. DJANGO BLOG APPLICATION DETAIL LIST
# Creating blog Posts list templates where we will design 
templates to display blog posts
Creating blog posts detail view where we will add blog post view 
function to display single post details
Creating blog posts detail templates where we will add a 
template to display details of a single post
Creating blog posts pagination feature where we will add 
posts pagination
Creating blog posts related posts where we will add a similar 
posts feature
Creating blog posts comment feature where we will learn 
about django forms and add a post comments feature
Creating a recent posts feature where we will add a recent posts 
feature
Creating blog posts search feature where we will add a blog 
posts search feature
Creating a blog posts Categories where we will add a blog 
categories feature
Creating User Registration and Login where we will add a user 
management system
Creating blog posts popular authors feature where we will 
add a feature that displays authors with most posts
#
#
#
#
#
#
#
#
#
#
The Blog app project Details
2
6. Creating Django Blog Application
Creating an app in django is easy and straight forward. Follow the 
steps below.
C:\Users\winst\OneDrive\Desktop\django_blog>venv\scripts\activate
(venv) C:\Users\winst\OneDrive\Desktop\django_blog>cd mysite
(venv) C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python manage.py startapp blog
(venv) C:\Users\winst\OneDrive\Desktop\django_blog\mysite>. 
1. Navigate to the root of your project. Assuming the virtual 
environment is active,if not,please activate it, and enter the following 
command in your console.
Python manage.py startapp blog
Below is a list of steps I followed to first activate the environment, 
change from the project directory into the mysite project directory 
then used the command above to create our blog app. Startapp is a 
command in the manage.py which is used to create a new django app.
The Django app that gets created is also a Python package with a few 
default modules that are predefined by Django. Below is a screenshot of 
what the blog app package contains:
6.1 Creating the blog App
2
7. The Blog app package files
Current project tree structure can be illustrated in the Django 
project tree view below. Let us use it to go through what each of the 
modules in the created app are used for.
7.1 Project Tree structure
1 2
3
6
7. Blog App package files(design philosophy)
First things first. It must be noted that Django is a Model-
View-Controller(MVC) framework. MVC is a software design 
pattern that aims to separate an application into three interconnected 
parts. 
Model which provides the interface with the database containing 
data for the application. 
1
View which decides what information to present to the user and 
collects information from the user. 
2
Controller which manages business logic for the application and 
acts as an information broker between the model and the view. 
3
Django implements the MVC in a slightly different way. It uses the Model 
Template View(MTV/MVT) style as illustrated in the figure below. 
7.2 The App structure and MVC/MVT Pattern
1 2
3
6
Back to our app files. The moduls created in the app serve 
to implement the Django’s Model-View-Template(MVT) 
framework. Here is what each of these files do in this design decision:
apps.py: This module contains a configuration class named after your 
app(BlogConfig in our case). This class configures and links this package 
as an app to the main project in the settings.py module under the 
INSTALLED_APPS list object. See the illustration below
1
7.Blog app package files(their roles)
7.3 The App structure(apps) and MVC/MVT Pattern
1 2
3
6
admin.py: This module help us to connect our app models to the 
django admin site that gets installed when we create the project. The 
admin site help us populate our app models with data.
2
Once you get this set up, your Post model will be registered and made 
available in the admin site as we will see in the next chapter. The admin 
site is also an app but you may not be able to see it until you open the 
libs folder of your virtual environment. Of course , it is registered in the 
INSTALLED_APPS list object of the project’s settings.py module.
7.Blog app package files(their roles)
7.4 The App structure(admin) and MVC/MVT Pattern
1 2
3
6
model.py: The model provides the interface with the database 
containing data for the application. Django uses an Object-relational 
Mapper (ORM) to interact with the database instead of standard SQL 
queries. ORM is a powerful programming technique that allows a 
developer to create python classes and attributes that generate database 
tables and their attributes(columns). Below is an illustration of the 
comparison between using SQL statements and ORM .The model in django
remains what it is in the MVC,an abstraction to the database access
3
7.Blog app package files(their roles)
7.4 The App structure(Models) and MVC/MVT Pattern
2
3
6
In Django, the model is the object mapped to the database. When you 
create a model, Django creates a corresponding table in the database 
,without writing a single line of SQL. The created table name is prefixed 
with the name of your Django application,blog_post(where blog is the 
name of our application and post is the name of the model) .See 
illustration below showing the table created from a Post model.
7.Blog app package files(their roles)
7.4 The App structure(Model) and MVC/MVT Pattern
1 2
3
6
The model also links related information in the database by using the 
foreign keys. That constitutes the mapping of the relationships between 
the created database tables or call them models. See illustration below 
showing the use of foreign keys on models to map relations between 
models:
7.Blog app package files(their roles)
7.4 The App structure(Model) and MVC/MVT Pattern
2
3
6
4 views.py: In essence, views are chunks of logic that accept incoming 
requests to a URL in your app and outputs the proper response. They are 
the information brokers of a Django application. A view sourcesdata 
from your database (or an external data source or service) and delivers 
it to a template. They are either python functions ,or python methods in 
case of class based views, that receive a request as a parameter, and 
returns a response that contain a template and context object. In 
Djano’s(MVT),the view(V) substitutes the control(C) in the MVC
pattern,while the Template(T) substitutes the View in the MVC design.
7.Blog app package files(their roles)
7.4 The App structure(Views) and MVC/MVT Pattern
2
3
6
8. Registering the app to the project
The Django framework is not famous for no reason. As 
mentioned in earlier chapters , it uses the python 
packages(apps) to create different sections(blog/cart/users) 
of the web application. These apps make Django very 
extensible. We can upgrade the web app by adding separate 
functionality by adding different apps.
In this section we will take a look at how to connect our blog app to the main 
Django project, mysite in our case. From the previous section we learnt that 
the app.py module in the created app(blog in our case) contains a 
configuration class which is used to add it(the new app) to the main project 
through the INSTALLED_APPS list object in the settings.py module of the 
main project. 
Open the mysite folder and add the code below to the INSTALLED_APPS list 
object.
'blog.apps.BlogConfig',
8.1 Install/register the App to the main project
2
3
6
Now the settings.py INSTALLED_APPS list object should look like the one 
below
INSTALLED_APPS= [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#blog app
'blog.apps.BlogConfig',]
Below is an illustration of what happens.
 The BlogConfig class which inherits from AppConfig is automatically created when 
creating the app using the python manage.py startapp command.
 The new app(blog) is added to the list of apps by adding this AppConfig(BlogConfig
in our case). And that adds our blog app to the main project
8. Registering the app to the project
Install/register the App to the main project
2
3
6
9. Creating blog Post Model
As stated in our earlier chapter,a model is a Python class 
that subclasses django.db.models.Model, in which each 
attribute represents a database field(column), and each 
model(class) represents a database table. When we create a 
model, Django provides us with an API to query objects in 
the database easily.
In this section,we will create our blog application database models. When we 
create a Django app with python manage.py startapp,Django a models.py 
module in which we define our application models.
Open the blog folder and add the code below to the model.py module to 
create Post model.
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
STATUS_CHOICES = ( ('draft', 'Draft'),('published', 'Published'),)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250,unique_for_date='publish')
author = models.ForeignKey(User,on_delete=models.CASCADE, 
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')
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
9.1 Creating blog database models
9.1 Create blog database tables
2
3
6
9. Creating blog Post Model
title: This is the field for the post title. This field is CharField, which translates 
into a VARCHAR column in the SQL database.
slug: A slug is a short label that contains only letters, numbers,underscores,or
hyphens. We will use the slug field to build beautiful, URLs for our blog posts. 
We have added the unique_for_date parameter to this field so that we can 
build URLs for posts using their publish date and slug.
author: This field is a foreign key. It defines a many-to-one relationship. We 
are saying each post is written by a user, and a user can write any number of 
posts. Django will create a foreign key in the database using the primary key 
of the related model. In this case, the User model of the Django
authentication system. The on_delete parameter specifies the behavior to 
adopt when the referenced object is deleted. Using CASCADE, we specify 
that when the referenced user is deleted, the database will also delete its 
related blog posts. We specify the name of the reverse relationship, from 
User to Post, with the related_name attribute. This will allow us to access 
related objects easily. 
body: This is the body of the post. This field is a text field,which translates 
into a TEXT column in the SQL database.
publish: This datetime indicates when the post was published.We use 
Django's timezone now method as the default value.This returns the current 
datetime in a timezone-aware format.
created: This datetime indicates when the post was created.Since we are 
using auto_now_add here, the date will be saved automatically when 
creating an object.
updated: This datetime indicates the last time the post was updated. Since 
we are using auto_now here, the date will be updated automatically when 
saving an object.
status: This field shows the status of a post. We use a choices parameter, so 
the value of this field can only be set to one of the given choices.
9.2 Explaining the created field types and their usage
2
3
6
9. Creating blog Post Model
The Meta class inside the model contains metadata. We need to sort results 
in the publish field in descending order by default when we query the 
database. We specify descending order using the negative prefix. By doing 
so, posts published recently will appear first.
The __str__() method is the default human-readable representation
of the object that will be used in many places, such as the administration 
site(more on admin site later). Creating and applying
migrations
9.3 Creating and applying database migrations
What we have done so far is modeling the table and fields we need to have 
in our blog application. We have not yet created these tables and fields in 
the actual database. To create these tables and fields(columns),we need to 
first have a database,then create these tables. 
Fortunately,Django comes with a pre-configured sqlite database in the 
settings.py module. When we first run our django application,an sqlite
database was created in our project root folder. We don’t have to separately 
install sqlite as it comes as an inbuilt package of the Python programming 
language. And Django simply points to it and enables the sqlite3 database 
file to be created once we run the project.
To create our Post model table,we will use the Django’s built in migration 
system that tracks the changes done to models. The migration system uses 
the python manage.py makemigrations command to propagate any model 
changes into the database. The python manage.py migrate command 
applies migrations for all applications listed in INSTALLED_APPS and 
synchronizes the database with the current models and existing migrations.
Open the console in the main project directory to run the the python 
manage.py makemigrations command. Be sure the venv is activated like 
below
2
3
6
9. Creating blog Post Model
When we run our project for the first time,the project runs but with these 
red lines informing us that we have some migrations that are not applied.
You have 18 unapplied migration(s). Your project may not work properly 
until you apply the migrations for app(s): admin, auth, contenttypes, 
sessions.
Run 'python manage.py migrate' to apply them.
What it means is that Django comes with pre-installed applications that have 
their database migrations ready to be synced to our database. Comment 
everything in the models.py that we just created and run thepython 
manage.py migrate command.
C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python manage.py 
migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
9.3 Creating and applying database migrations
2
3
9. Creating blog Post Model
The migrations listed above are the changes that have occurred in our 
database. Below is a screen-shot of a list of tables that they create in our 
sqlite3 database file.
Now let us uncomment the code in our blog/models.py module. Run the 
python manage.py makemigrations blog .
You should see the following output:
C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python manage.py 
makemigrations blog
Migrations for 'blog':
blog\migrations\0001_initial.py
- Create model Post
Django just created the 0001_initial.py file inside the migrations directory of 
the blog application.Open that file to see how a migration appears. A closer 
look reveals that a migration specifies dependencies on other migrations and 
operations to perform in the database to synchronize it with model changes.
Now Let's sync our database with the new model. Run python manage.py 
migrate. You should see the following output:
C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python manage.py 
migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0001_initial... OK
9.3 Creating and applying database migrations
2
3
9. Creating blog Post Model
After applying migrations, the database reflects the current status of our 
models.Below is the screenshot of our updated database.
A new table named after the name of the app and model we defined in the 
model.py got created(blog_post). Also take note the number of tables 
increased from 11 to 12.
9.3 Creating and applying database migrations
2
3
6
10.Adding Blog Post Model to Admin site
Django comes with a built-in administration interface that is 
used for editing content. The Django admin site is populated 
by reading our model metadata and provide an interface for 
editing content. The django admin app is already defined and 
added in the INSTALLED_APPS list in the settings.py.
The admin app is defined in the django.contrib.admin. To access it,first enter 
the python manage.py runserver command to start the server. Then 
navigate to http://localhost:8000/admin/ in your web browser. It will 
redirect to the login page in the screenshot below.
To login we need to create a super user using the console as shown below.
C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python manage.py 
createsuperuser
Username (leave blank to use 'winst'): winston23
Email address: winston@gmail.com
Password:
Password (again):
Superuser created successfully.
10.1 Registering models to the Django admin App
http://localhost:8000/admin/
2
3
6
10.Adding Blog Post Model to Admin site
We can now use these credentials to login to the admin site. Below is the 
screenshot of the admin site for our site. 
To make our Post model available in the admin site we must add it. To do that 
, open the blog/admin.py module add the code below.
We only have the Group and User models populated in the admin site. We 
have not defined these two! They are part of the Django authentication 
framework located in django.contrib.auth and is among the prepopulated 
apps in the INSTALLED_APPS list object. Clicking on Users,we see the user 
created in the console,one we used to login into the admin site. Our Post 
model created in the blog application has a relationship with this User model 
through the author. 
10.1 Registering models to the Django admin App
2
3
6
10. Adding Blog Post Model to Admin site
Now let us reload the admin site. We should see the Post model added as 
seen in the screenshot below.
from django.contrib import admin
from .models import Post
admin.site.register(Post)
When a model is registered in the Django admin site, we get a user-friendly 
interface generated by our models that allows us to list, edit, create, and 
delete objects in a simple way. Now let us create a post using the django
admin by clicking on add button as seen in the screenshot below:
10.1 Registering models to the Django admin App
2
3
6
10. Adding Blog Post Model to Admin site
Infact we can customize even further how the admin site displays the models. 
Below we are using the ModelAdmin class to 
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish','status')
We are registering our model in the admin site using a custom class(PostAdmin) 
that inherits from ModelAdmin. The list_display attribute allows us to set the 
fields of our model that we want to display in the admin object list page. The 
@admin.register() decorator does the same function as the 
admin.site.register() function, except it registers the ModelAdmin class that it 
decorates. Below is how our Post model looks.
Here are some more admin site customizations. You can get familiar with these 
attributes from the django docs.
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish','status')
list_filter = ('status', 'created', 'publish', 'author')
search_fields = ('title', 'body')
prepopulated_fields = {'slug': ('title',)}
10.1 Registering models to the Django admin App
2
3
6
11. Creating blog posts list and detail 
views
A Djangao view is just a Python function/method that 
receives a web requeast and returns a web response. 
Normally, users send resource requests to different end-
points. The django url patterns in the main site project route 
these requests to different app level urls. The app level url
patterns match the end-points(resources eg “blog/”) to view 
functions. These view functions return response with 
related template and context objects back to the user as 
illustrated below.
11.1 Creating App Views
2
3
11. Creating blog posts list view
Views in Django’s MVT implementation of the MVC work as controllers in as 
far as the MVC design pattern holds to reference. They bridge the models 
and Templates together. The django’s Object Relational Mapper is brought to 
life in the View where it is used to query the data objects from the 
models(tables). Once all the necessary data processing and calculations are 
done,these data objects are rendered to the user as response object in the 
context.
Talking of data and the ORM requires that we at least need to get familiar 
with how the Django ORM works. Let’s take a look at how we build querysets 
in django.
11.1 Creating objects
Once we have our data models created, Django gives us a free and very 
flexible API to interact with these models.Django provides atleast one 
manager for each model,and it is called the objects.We use this manager to 
access our models. 
Now let us use the terminal to interact with the objects related to the models 
we have so far. Openthe terminal in our project directory and launch shell.
Python manage.py shell
>>> from django.contrib.auth.models import User
>>> from blog.models import Post
>>> user1 = User.objects.get(username='winston23')
>>> post2=Post(title='Django ORM is fun and very flexible',slug='django-
orm-is-flexible',body='The first time I used it I knew I was going to love 
using it',author=user1)
>>> post2.save()
>>>
11.1 Creating App Views(using shell)
2
3
11. Creating blog posts list and detail 
view
 In this console session,we are first retrieving the user object with the 
username winston23.
 We use the get() method to retrieve a single object from the database.
We create a Post instance with a title, slug, and body, then we set the user 
we previously retrieved as the author of the post.
 Finally, we save the Post object to the database using the save() method:
11.2 Updating objects
>>> post2.title='This is an updated post title for our post'
>>> post2.save()
>>> 
If we check our admin dashboard for post list,we should see our new post 
created using the console session is available as shown below.
 Since we are calling the same object(post2) and using dot notation to 
access its title attribute,whatever we write as its value will be the 
new,updated value of this attribute.Check the screenshot below .
 This time around,the save() method performs an update.
11.1 Creating App Views(List view)
2
3
11. Creating blog posts list and detail 
view
11.4 Using the filter method
>>> winston_posts=Post.objects.filter(author__username='winston23')
>>> print(winston_posts)
, ]>
>>>
 As stated earlier,each model has one default manager called objects. We 
can access all objects of the model by using this manager as seen in the 
first line of our console session above.
 Earlier we accessed a single object by using Post.objects.get() method. 
Here the get() method accesses a single object from the manager. 
>>> all_posts = Post.objects.all()
>>> print(all_posts)
, ]>
>>>
11.3 Retrieving objects
 The manager has the filter() method, we can retrieve all posts linked to a 
particular author as in the QuerySet above. We can also filter by multiple 
fields like below.
>>> 
win_posts_2021=Post.objects.filter(publish__year=2021,author__usernam
e='winston23')
>>> print(win_posts_2021)
, ]>
>>>
11.1 Creating App Views(Using shell)
2
3
11. Creating blog posts list and detail 
views
 To delete an object, you need to access the object instance and use the 
delete() method as above. Below is the screenshot of our admin site 
showing only one post remaining after the delete action.
>>> deleted_post=Post.objects.get(id=1)
>>> deleted_post.delete()
(1, {'blog.Post': 1})
>>>
11.5 Deleting objects
Before we can move on to discussing the views,you need to take note of 
these points:
Queries with field lookup methods are built using two underscores, for
example, author__username
Deleting objects will also delete any dependent relationships for
ForeignKey objects defined with on_delete set to CASCADE.
11.1 Creating App Views(Using shell)
2
3
11. Creating blog posts list and detail 
views
With the knowledge of how to use the ORM works, we can now move on
to building the views of our blog application. 
11.6 Creating Custom managers
We will need to have two different views for querying posts. The first,a
post_list view, will be used to define a QuerySet that will access all posts in 
our model. And the second,post_detail view, will be used to define a 
QuerySet that will access a single post and display its details.
But before we can create our views,we first need to take a step backward to 
our model managers. Remember we said Django models come with a 
default manager called objects. We can create custom managers too. So we 
need to create a custom manager that returns our objects slightly different 
based on our preference. We need to return only post objects that are 
published. So open the models.py and write the following code just above 
our Post model.
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager,self).get_queryset()
.filter(status='published')
Once that is added, add the lines below to the attributes of the Post model.
class Post(models.Model):
………………….
…………………..
objects = models.Manager() # The default manager.
published = PublishedManager() # Our custom manager.
Now we do not have to use Post.objects.all(),although we still have access 
to it. Our interest rather is to only query posts that are published,and now 
we can use Post.published.all()
11.1 Creating App Views(Custom managers)
2
3
11. Creating blog posts list and detail 
views
Let's create a post_list and post_detail views to display the list of posts and 
details of each post that we have in the database. Open and edit the views.py
file of our blog application.Add the code below. 
from django.shortcuts import render
from .models import Post
#post list view
def post_list(request):
posts = Post.published.all()
return render(request,'blog/post/list.html',{'posts': posts})
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, 
slug=post,status='published',publish__year=year,publish__month=month,publish__d
ay=day)
return render(request,'blog/post/detail.html',{'post': post})
 The post_list and post_detail views take the request object as their first 
parameter.
 The request parameter is required by all views. 
 In the view, we are assigning a QuerySet which retrieves all the posts with the 
published status using the published manager we created in the previous 
section to posts variable.
 Finally, we are using the render() shortcut provided by Django to
render the list of posts in our posts variable with the given template.
 The render function takes the request object, the template path, and the 
context variables to render the given template.
 The render function returns an HttpResponse object with the rendered 
HTML code. 
 In the detail view, we use the get_object_or_404() shortcut to retrieve the 
desired post.
 The detail view takes year, month, day, and post parameters to retrieve a 
published post with the given slug and date.
11.6 Creating App Views(List view)
2
3
6
12. Adding and configuring the blog app urls
The Django framework implements the client/server 
archtecture. In the http and the web protocol topic we 
learnt that the http uses the request and responses to 
access different resources on the internet. The resources 
are nothing but various end-points stored on servers we 
connect to on the internet. These resources are defined or 
located in form of urls. In other words,the urls are 
addresses to these resources.
In this section we will take a look at how to configure our blog app urls and 
then to the main site urls. The urls we configure in the project’s urls.py 
simply connects the blog app as a resource to the main site. They are project 
level urls. That is to say,they connect/map different apps to the main project. 
The different url patterns at the app level(blog app) will match and point to 
resources each of these views will be interacting with. Yes, the views(which 
work as controllers in the MVC pattern) are the actual end-points that map 
templates to data . Let’s add the url patterns to our project. First we have to 
add the blog app pattern to the main project’s url.py. 
Open the mysite folder and add the code below to the urls.py module.
12.1 Creating App URLs
2
6
12. Adding and configuring the blog app urls
from django.contrib import admin
from django.urls import path,include
urlpatterns = [ path('admin/', admin.site.urls),
path('blog/',include('blog.urls', namespace='blog')), ]
Here,we first import the path and include functions from the django.urls
module. The path function adds items(end-point eg “blog/”) to the patterns 
while include function adds the url patterns to be included into this path . 
Also note that we have imported the admin.This is an app that comes and is 
installed with django when we create the django project.It is one of the apps 
you will find added by default to the list of INSTALLED_APPS object. Below is 
an illustration of how the main site urls will look each time we add a new 
app to our project.
12.1 Creating App URLs
2
6
12. Adding and configuring the blog app urls
from django.urls import path
from . import views
app_name = 'blog‘
urlpatterns =
[path(‘ ', views.post_list, name='post_list'),
path('////',views.post_detail,na
me='post_detail'),
]
Next we need to define url patterns for the app level, the blog app in our 
case. First of all , create a urls.py file in the blog directory as it is not installed 
by default. Open the file and add the code below.
 In the code above, we define an application namespace with the 
app_name variable. 
 This will allow us to organize URLs by application and use the name when 
referring to them. 
 We define our patterns using the path() function. The first URL pattern 
doesn't take any arguments and is mapped to the post_list view.
12.1 Creating App URLs
2
6
13. Creating blog posts list and detail 
templates
We have created the models, views and URL patterns for our blog application.
The remain piece to complete the MVC/MVT design patterns for a fully usable 
web application is the Template. The templates are the html and its associated 
front-end code that eventually builds what the user interacts with.
All our templates will be created using tailwind css utility framework. I 
therefore encourage you to visit the tailwindcss.com website for 
documentation and quick guides on how it works , otherwise, its more like 
bootstrap by without components. You create components out of utility 
classes. Below is the final look of what we want our blog home page to look 
like.
To start with we will create our post listing,list.html and our post detail, 
detail.html templates. 
Open blog folder and create a folder named templates in it. Inside it create 
another folder and name it blog. Create a file named base.html and a folder 
named post inside this sub-folder. Finally, create two other templates 
named list.html and detail.html inside our post folder. Below is the tree 
view of how these folders and files should look like.
13.1 Creating App Templates
tailwindcss.com
2
6
13. Creating blog posts list and detail 
templates
The base.html file will include the main HTML structure of our site while the 
list.html and detail.html files will inherit from the base.html. Now create 
another folder,name it static, inside our blog app folder,just next to templates 
folder. Head over to the CDN link for tailwind css, extract only the 
url(https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css) paste in the 
browser search bar. You should have the whole tailwind css file displayed in 
the browser. Just copy it. 
Open the static folder we just created and create a tailwind.min.css file and 
paste the tailwind css code we copied from the browser..note that this is only 
for development purposes,and only my preference…you may use the CDN 
directly. But for the purpose of demonstrating how to link static files, follow 
these steps.
Next,you need to open the base.html and paste the code you will download 
from this link. It is mostly a tailwind css design as well as some Django 
template syntax. Below are some highlights from the code you downloaded.
13.2 App Templates Folder Structure
http://www.codesnnippets.com/base.html
2
6
13. Creating blog posts list templates 
and Detail Templates
{% load static %}
{% block title %}{% endblock %}
{% block content %}
{% endblock %}
Django has its own template language that allows us to specify how data is 
displayed. It uses template tags, template variables, and template filters.
 Template tags control the rendering of the template and look like {% tag %}.
 When the template is rendered template variables are replaced with data 
values and look like {{ variable }}.
 Template filters are used for modifying variables for displaying and look like 
{{ variable|filter }}.
From the base.html template above,{% load static %} tells Django to load the 
static template tags that are provided by the django.contrib.staticfiles
application, which is already added in the INSTALLED_APPS. It allows us to 
use the {% static %} template filter throughout this template. With this 
template filter, you can include static files, such as the tailwind.css file , that 
we have under the static/ directory of the blog application.
13.2 Creating App Templates(the base template)
2
6
13. Creating blog posts list templates 
and Detail Templates
In the template we have two {% block %} tags. These tell Django that we 
want to define a block in that area. Templates that inherit from this base 
template can fill in the blocks with content. We have defined a block called 
title and a block called content.
{% extends "blog/base.html" %}
{% block title %}My Blog{% endblock %}
{% block content %}
Posts
{% for post in posts %}
{{ 
post.title }}
Published {{ post.publish }} by {{ post.author }}
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% endblock %}
The {% extends %} template tag instructs Django to allow this template to 
inherit from the blog/base.html template.The title and content blocks fill in 
the base template with content from this template.
13.3 Creating App Templates(the post_list template)
2
6
13. Creating blog posts list templates 
and Detail Templates
We are using the for loop to iterate through the posts and display their title, 
date, author, and body, including a link in the title to the canonical URL of 
the post. We use two template filters: truncatewords to limit the value to the 
number of words to be displayed, and linebreaks converts the output into
HTML line breaks. 
Now type the python manage.py runserver to start our development server. 
Once it starts,navigate to http://localhost:8000/blog/ with a web browser. 
If we have some posts in the database,we should have our blog posts 
displayed like below.
Although not what we entirely want, the overall functionality and proper 
styling and formats give us a nicely displayed list of posts.
Next,we need to create our detail.html template and display the details of 
each post in our web site. 
Open the detail.html template inside our templates and paste the code 
below.
13.3 Creating App Templates(the post_list template)
http://localhost:8000/blog/
2
6
13. Creating blog posts list and detail 
templates
The Django template syntax in here is no so diferent from the list.html 
template, so it should be self explanatory. Lets return to our browser and 
click on one of the post titles to take a look at the detail view of a post. You 
should see something like the one in the screenshot below.
{% extends "blog/base.html" %}
{% block title %}
{{ post.title }}
{% endblock %}
{% block content %} 
{{ post.title }} 
 By {{ post.author }}Published 
{{ post.publish }}
 
{{ post.body|linebreaks }}
 
 
{% endblock %}
13.4 Creating App Templates(the post_detail template)
2
6
13. Creating blog posts list templates 
and Detail Templates
Not so bad! Here we have a post detail displayed with the title, author,date
and body text formatted with tailwind css to improve the readability. We will 
keep improving and making some upgrades to this minimal blog application 
features as we progress to the next chapters.
13.4 Creating App Templates(the post_detail template)
2
3
6
14. Adding blog posts pagination feature
What we have at the moment is a functioning blog 
application. The next steps are just features that are 
required for a blog to deliver content in a user friendly and 
convenient way , thereby improving user experience. They 
should solve a problem while enhancing its usability. 
Pagination allow users to load posts in regulated way. We 
may have 100s of blog posts on our site. We don’t need our 
users to be presented with all those blogs at once in a 
single screen! We have to split that content into different 
pages, with each page serving a specified number of posts. 
That is what we aim to implement in this chapter.
To our rescue , Django has a built-in pagination class that allows us to 
manage paginated data easily . All we need is to import the Django paginator
classes and modify the view in which we intend to use them.
Open the blog/views.py file and edit our post_list view to look like the one 
below.
Also worth noting is that in Django, we can create function-based views or 
class-based views. But whatever you use, understand that class-based views 
do not replace function-based views. They simply facilitate the reusability of 
views through inheritance. All in all, views will always be functions. They can 
be either normal function views or methods under a class. We are going to 
see how to implement our pagination using both methods.
13.1 Introduction
2
3
6
14. Adding blog posts pagination feature
 Here,we are importing the Paginator, EmptyPage, PageNotAnInteger
from django.core.paginator where they are defined.
 We instantiate the Paginator class with the number of objects we want to 
display on each page i.e 3 posts.
 We use the request.GET.get('page') parameter that returns the current 
page number.
 We access the objects(posts) for the desired page by calling the page()
method of Paginator.
 If the page parameter is not an integer, we retrieve the first page of 
results. If this parameter is a number higher than the last page of results, 
we will retrieve the last page.
 Finally, we pass the page number and retrieved objects(posts) to the 
template.
from django.core.paginator import Paginator, EmptyPage, 
PageNotAnInteger
..................................
..................................
def post_list(request):
object_list = Post.published.all()
paginator = Paginator(object_list, 3) # 3 posts in each page
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger: 
# If page is not an integer deliver the first page
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request,'blog/post/list.html',{'page': page,'posts': posts})
14.2 Function based pagination view
2
3
6
14. Adding blog posts pagination feature
The pagination needs to be independent from all the templates so that we 
can simply inject it into any other template that needs to use pagination. 
Open the templates/ folder of our blog app and create a template named 
pagination.html.
The pagination template needs a Page object in order to render previous 
and next links and to display the current page and total pages of results. 
Let's return to the blog/post/list.html template and include the pagination.html 
template at the bottom of the {% content %} block, as below.
{% block content %}
{% include "pagination.html" with page=posts %}
{% endblock %}
14.2 Function based pagination view
2
3
6
14. Adding blog posts pagination feature
{% if posts.has_other_pages %}
{% if posts.has_previous %}
 
{% else %}
{% endif %} 
{% for i in posts.paginator.page_range %}
{% if posts.number == i %} {{ i
}} {% else %} 
{{ i }} {% endif %} {% endfor %}
{% if posts.has_next %}
{% else %} 
{% endif %} 
{% endif %}
14.3 Function based pagination view( Adding Tailwind cssLibrary)
2
3
6
14. Adding blog posts pagination feature
Now run the python manage.py runserver to start the development 
server. With your browser,navigate to http://localhost:8000/blog/. Below is 
the screenshot of the results.
Notice that in the code I am using Paginator.page_range , which is a 1-
based range iterator of page numbers, i.e. yielding [1, 2, 3, 4]. This is an 
inbuilt property of the Paginator class. Am using it to iterate through all the 
available pages in the page_number property and display each page in the 
pagination template.
14.2 Function based pagination view
http://localhost:8000/blog/
https://docs.djangoproject.com/en/3.2/ref/paginator/
2
3
6
13. Adding blog posts paginationfeature
Class-based views allow us to define views as class methods. Out of the box 
Django provides base view classes for this. These classes inherit from the 
View class, which handles HTTP method dispatching and other common 
functionalities.
Class based views offer the following advantages:
 They help to organize code related to HTTP methods, such as GET, 
POST, or PUT, in separate methods instead of using conditional 
branching.
 They make usage of multiple inheritance to create reusable view classes 
(mixins)
 We are using a specific custom queryset instead of retrieving all objects.
 We use the context variable posts for the query results. The default 
variable is object_list if we don't specify any context_object_name.
 We paginate the result displaying three objects/posts per page and then 
we use a custom template to render the page.
from django.views.generic import ListView
..................................
..................................
class PostListView(ListView):
queryset = Post.published.all()
context_object_name = 'posts'
paginate_by = 3
template_name = 'blog/post/list.html'
Modifying blog app urls.py for a class based view.
Since we are using a class method to implement a view,we need to modify our 
posts/ url pattern to the one below. We need to comment out the function 
based url pattern.
14.3 Class based pagination view
2
3
6
13. Adding blog posts pagination feature
urlpatterns = [
# post views
# path('', views.post_list, name='post_list'),
path('', views.PostListView.as_view(), name='post_list'),
path('////',views.post_detail,
name='post_detail'),
]
Modifying blog app list.html template to pass in pagination template.
The final step is to pass the right variable to display the pagination to the 
lit.html template.The Django's ListView generic view passes the selected 
page in a variable called page_obj. Below is how we pass the page_obj to the 
template.
{% block content %}
{% include “classbasedpagination.html" with page=page_obj %}
{% endblock %}
The last thing to work on is modifying the pagination template. Here we will 
use classbasedpagination.html template. Unfortunetely it’s a large file to fit 
in a page. Here is the link to code. Once you download it,put it in the same 
directory as the pagination.html
14.3 Class based pagination view
http://www.googledrive.com/
2
3
6
13. Adding blog posts pagination feature
Start the development server again using python manage.py runserver. 
Open the browser to http://localhost:8000/blog/. We have the same results 
as for the function based view.
14.3 Class based pagination view
http://localhost:8000/blog/
2
3
6
15. Adding a tagging feature to posts
Tags are a way to categorize content or group posts under a 
label. It is another way of creating categories for easily 
accessing posts. We use tags to access all posts under 
certain tags, e.g. all posts under “python” could be accessed 
by clicking on a python tag. 
In this chapter, we will learn how to create a tagging 
feature for our blog application. Using a third party library 
and in the process learn how to use external libraries for 
django.
As mentioned in the introduction, we will create a way to tag our posts by 
integrating a third-party Django tagging application in our project. The 
extension we will use is called django-taggit. The django-taggit module is a 
reusable application that offers a Tag model and a manager to easily add 
tags to any model. 
15.1 Introduction
2
3
6
15. Adding a tagging feature to posts
First we need to install django-taggit by running the command below. 
Make sure your venv is activated as below.
(venv) C:\Users\winst\OneDrive\Desktop\django_blog\mysite>pip install 
django-taggit
Once installed, we need to add this reusable app to our django settings 
INSTALLED_APPS list. Open the settings.py module in our main project 
and add the “tagged” to the list as shown below.
INSTALLED_APPS = [
# ...
'blog.apps.BlogConfig',
'taggit',
]
Tags need to be associated with a post. We therefore need to add the tags to 
our post model. Lets Open the models.py file of our blog application and 
add the TaggableManager manager provided by django-taggit to the Post 
model as shown below.
from taggit.managers import TaggableManager
class Post(models.Model):
# .........
tags = TaggableManager()
Since we have modified our model,we ned to run migration and then sync 
them to the database by migrating them with commands below.
(venv) C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python 
manage.py makemigrations
(venv) C:\Users\winst\OneDrive\Desktop\django_blog\mysite>python 
manage.py migrate
15.2 Installing and Configuring django-taggit
2
3
6
15. Adding a tagging feature to posts
There are a number of ways to add tags to our posts,but we will use the 
django admin site to add them.
Open the console and run python manage.py runserver to start the 
development server. Then login to the admin site by navigating to 
http://localhost:8000/admin/blog/post/. Click at any post ,you should see a 
screen like the one in the screenshot below. The tags input allows us to 
add tags to our posts. 
Go ahead,update all the posts with tags to each of them.
We can also add tags by using http://localhost:8000/admin/taggit/tag/ . 
This will open a tags manager screen which allows us to add tags to items 
by selecting their ids. I prefer just directly adding tags to blogs as done 
above.
15.3 Adding tags to posts
http://localhost:8000/admin/blog/post/
http://localhost:8000/admin/taggit/tag/
2
3
6
15. Adding a tagging feature to posts
Since we have our models ready with tags,we now need a way to display 
them to our templates. To do that add the code below just below the title in 
our list.html template.
{% for tag in post.tags.all %}
 {{ tag.name }} 
{% endfor %}
We are using a for loop to iterate through our tags in the post model. Then 
we use the tag.name toextract each tag and render them in our html 
template. Much of the stuff you see wrapped in class are tailwind css utilities 
that help us to nicely style the tags. Below is the screenshot of the posts list.
15.4 Modifying Templates to display tags
2
3
6
14. Adding a tagging feature to posts
We need the tags to display even on each post detail.Modify the detail.html 
template in our blog app templates as below.
{% for tag in post.tags.all %}
 {{ tag.name }} 
{% endfor %}
Assuming the development server is still running,navigate to 
http://localhost:8000/blog/2021/11/22/why-is-django-so-popular/ .You 
should see the results similar to the screenshot below.
15.4 Modifying Templates to display tags
http://localhost:8000/blog/2021/11/22/why-is-django-so-popular/
2
3
15. Adding a tagging feature to posts
As it is, at the moment our tags cant display posts linked to it. Do achieve that 
(listing posts by tags) we will should edit our post_list view to let users list all 
posts tagged with a specific tag. 
Open the views.py file of your blog application,
import the Tag model form django-taggit, and change the post_list view
to optionally filter posts by a tag, as follows:.
Open our views.py in the blog application and modify it as seen below.
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
The post_list view above:
 Takes an optional tag_slug parameter which has

Mais conteúdos dessa disciplina