- Published on
Get to know useful Django features
- Authors

- Name
- K N Anantha nandanan
- @Ananthan2k
Get to know useful Django features
Django is a powerful web framework that makes it easy to build complex web applications. One of the things that makes Django so powerful is its ability to handle forms, formsets, inlines, filters, querysets, and templates. In this blog post, we're going to take a closer look at each of these topics and see how they can be used to build amazing web applications.
Forms
Forms are the most common way to collect user input in a web application. Django provides a powerful form framework that makes it easy to create forms and validate user input. In this section, we'll take a look at how to create a simple form and how to validate user input.
Creating a form
To create a form, we need to create a class that inherits from the ModelForm class. The ModelForm class is a subclass of the Form class.
The ModelForm class provides a set of helper methods that make it easy to create forms and validate user input. For example, the ModelForm
class provides a save() method that saves the form data to the database. The ModelForm class also provides a clean() method that
validates user input. For example, let's take assume a Model called User that has some fields. We can create a form for the User model.
from django import forms
from .models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
- The
Metaclass is used to define the model and fields that the form will be based on. You can exclude fields from the form by using theexcludeattribute instead of thefieldsattribute. - There are other features that can be used to customize the form. For example, you can use the
widgetsattribute to specify the type of widget that should be used for each field. You can also use thelabelsattribute to specify the label for each field. - Furthermore, there are different form fields. For example, the
CharFieldis used to represent a text field. TheEmailFieldis used to represent an email field. TheDateFieldis used to represent a date field. TheDateTimeFieldis used to represent a date and time field etc. Let's take a look at how to use these fields, widgets, labels in our Form.
from django import forms
from .models import User
class UserForm(forms.ModelForm):
first_name = forms.CharField(label='First Name', max_length=100, widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Enter your first name'
}
))
last_name = forms.CharField(label='Last Name', max_length=100, widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Enter your last name'
}
))
email = forms.EmailField(label='Email', widget=forms.EmailInput(
attrs={
'class': 'form-control',
'placeholder': 'Enter your email'
}
))
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
exclude = ['date_joined']
- There are many other fields and widgets that can be used according to the need. You can refer to the documentation for more information.
How to use the form in a view ?
To use the form in a view, we need to create a view function that takes a request as an argument. The view function should return a response that contains the form. For example, let's create a view function that returns a form.
from django.shortcuts import render
from .forms import UserForm
def user_form_view(request):
form = UserForm()
return render(request, 'user_form.html', {'form': form})
- The
render()function is used to render a template. Therender()function takes three arguments. The first argument is the request. The second argument is the template name. The third argument is a dictionary that contains the context. The context is a dictionary that contains the variables that will be available in the template. In this case, the context contains the form variable. - The
user_form.htmltemplate can be created as follows.
{% extends 'base.html' %} {% block content %}
<form method="POST">
{% csrf_token %} {{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock %}
- The
form.as_ptag is used to render the form as a paragraph. Theform.as_tabletag is used to render the form as a table. Theform.as_ultag is used to render the form as an unordered list. - The
csrf_tokentag is used to render the CSRF token. The CSRF token is used to prevent Cross-Site Request Forgery attacks. The CSRF token is a hidden field that is used to validate the form. The CSRF token is automatically added to the form when themethodattribute is set toPOST. It's important to add the CSRF token to the form. Otherwise, the form will not be submitted because the CSRF token will not be validated. You can read more about CSRF tokens here.
How to validate user input ?
Now the above user_form_view function is used to render the form. However, the form is not used to collect user input. To collect user input,
we need to use the request.POST attribute. The request.POST attribute is a dictionary that contains the form data. For example, let's
modify the user_form_view function to collect user input.
from django.shortcuts import render
from .forms import UserForm
def user_form_view(request):
form = UserForm()
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'user_form.html', {'form': form})
-
The
form.is_valid()method is used to validate user input. If the user input is valid, theform.save()method is used to save the form data to the database. If the user input is invalid, theform.errorsattribute is used to get the errors. -
Sometimes, you might want to get the data from the form without saving it to the database. In this case, you can use the
form.cleaned_dataattribute. Theform.cleaned_dataattribute is a dictionary that contains the form data. For example, let's modify theuser_form_viewfunction to get the data from the form without saving it to the database.
from django.shortcuts import render
from .forms import UserForm
def user_form_view(request):
form = UserForm()
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
return render(request, 'user_form.html', {'form': form})
Note: The
form.cleaned_dataattribute is only available if theform.is_valid()method returnsTrue. And you can only use theget()method to get the data from theform.cleaned_dataattribute. For example,first_name = form.cleaned_data.get('first_name').
How to set initial values for a form ?
Sometimes, you might want to set initial values for a form. For example, let's say you want to create a form that allows users to update their
profile or to help user fill-in less predicatable information, like his birthday which could be taken from the database, we can customize the form
to set the initial values for the fields. For example, let's modify the user_form_view function to set the initial values for the form.
from django.shortcuts import render
from .forms import UserForm
def user_form_view(request):
form = UserForm()
if request.method == 'POST':
user = User.objects.get(id=request.user.id)
form = UserForm(request.POST)
if form.is_valid():
form.save()
else:
form = UserForm(initial={'birth_date': user.birth_date.strftime('%Y-%m-%d')})
return render(request, 'user_form.html', {'form': form})
- The
form = UserForm(initial={'birth_date': user.birth_date.strftime('%Y-%m-%d')})line is used to set the initial value for thebirth_datefield.
Note: The
request.userattribute is used to get the current user. Therequest.userattribute is only available if the user is authenticated. You can read more about authentication here.
Formsets
Formsets are a way to manage multiple forms in a single view. They are particularly useful when you need to handle a large number of forms in a single view. For example, imagine you have a website that allows users to create a list of items. Instead of creating a separate form for each item, you can use a formset to handle all of the forms in a single view. Let's take a look at how to use formsets.
Preparing a formset
Let's say we have the User model that we created in the previous section. We want to create a formset that allows users to add his/her social media
accounts. The User model has the following fields.
class User(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
email = models.EmailField()
date_joined = models.DateTimeField(auto_now_add=True)
- We want to create a formset that allows users to add his/her social media accounts. The
SocialMediaAccountmodel has the following fields.
class SocialMediaAccount(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
url = models.URLField()
- The
SocialMediaAccountmodel has a foreign key to theUsermodel. Theuserfield is used to store the user that owns the social media account.
What I have to come to use is the inlineformset_factory function to create a formset. The inlineformset_factory function takes three arguments.
The first argument is the parent model. The second argument is the child model. For example, let's create a formset that allows users to add his/her social media accounts. Let's create a new view called user_formset_view in the
views.py file.
from django.shortcuts import render
from .forms import UserForm
from .models import User, SocialMediaAccount
def user_formset_view(request):
UserFormSet = inlineformset_factory(User, SocialMediaAccount, fields=('name', 'url'), extra=1,
can_delete=False)
if request.method == 'POST':
form = UserForm(request.POST)
formset = UserFormSet(request.POST)
if form.is_valid() and formset.is_valid():
user = form.save()
for form in formset:
social_media_account = form.save(commit=False)
social_media_account.user = user
social_media_account.save()
else:
form = UserForm()
formset = UserFormSet()
return render(request, 'user_formset.html', {'formset': formset}, {'form': form})
So what's happening here? Let me explain is step by step.
-
The
inlineformset_factoryfunction is used to create a formset. Theinlineformset_factoryfunction takes three arguments.- The first argument isthe parent model.
- The second argument is the child model.
- The
extraargument is used to specify the number of extra forms that will be added to the formset. - The
can_deleteargument is used to specify whether the user can delete the forms in the formset. - The
fieldsargument is used to specify the fields that will be displayed in the formset.
-
Then, we check if the request method is
POST. If the request method isPOST, we create aUserForminstance and aUserFormSetinstance. -
Then, we check if the
UserForminstance and theUserFormSetinstance are valid. If they are valid, we save theUserForminstance to the database. Then, we loop through theUserFormSetinstance and save each form to the database. -
If the request method is not
POST, we create aUserForminstance and aUserFormSetinstance. -
Finally, we render the
user_formset.htmltemplate and pass theUserFormSetinstance along with theUserForminstance to the template.
What is difference between UserForm and UserFormSet?
When you create a form or formset object and pass it the request.POST data,
Django will automatically extract the relevant data from the request and use it to populate the form or formset fields.
For example, when you create a form object using form = UserForm(request.POST), Django will extract the data from the request.POST object that corresponds
to the fields in the UserForm, and use that data to populate the form. Similarly, when you create a formset object using formset = UserFormSet(request.POST),
Django will extract the data from the request.POST object that corresponds to the fields in the UserFormSet and use that data to populate the formset.
Creating a formset template
Now that we have created a formset, let's create a template to display the formset. Let's create a new file called user_formset.html in the templates folder.
{% extends 'base.html' %} {% block content %}
<h1>User Formset</h1>
<form method="POST">
{% csrf_token %} {{ form.as_p }} {{ formset.management_form }} {% for form in formset %} {{
form.as_p }} {% endfor %}
<input type="submit" value="Submit" />
</form>
{% endblock %}
So what's happening here? Let me explain is step by step.
- We extend the
base.htmltemplate. - Then, we display the
UserForminstance using theform.as_ptemplate tag. - Then, we display the
UserFormSetmanagement form using theformset.management_formtemplate tag. - Then, we loop through the
UserFormSetinstance and display each form using theform.as_ptemplate tag. - Finally, we display a submit button.
This is a very basic implementation of a formset. You can use the same approach to create more complex formsets.
Inlines
In django admin, out of the box has a lot of features and it's pretty easy to use. But if you want to customize the admin site, you can do that too. One of those is the need to add or edit related objects on the same page as the parent object. This is called inlines.
Creating an inline
Let's use the User model and the SocialMediaAccount model to create an inline. Assuming we have registered the User model and the SocialMediaAccount model
in the admin site, let's create a new class called SocialMediaAccountInline in the admin.py file.
from django.contrib import admin
from .models import User, SocialMediaAccount
class SocialMediaAccountInline(admin.TabularInline):
model = SocialMediaAccount
extra = 1
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
search_fields = ('first_name', 'last_name', 'email')
list_display = ('first_name', 'last_name', 'email')
inlines = [SocialMediaAccountInline]
This will add the SocialMediaAccount model as an inline to the User model in the admin site.
Different types of inlines
StackedInline- Displays the inline in a stacked format.TabularInline- Displays the inline in a tabular format.
Querysets
Querysets are the core of Django's ORM. Querysets allow you to read data from the database, filter data, order data, and much more. Querysets are lazy. This means that querysets are not evaluated until they are needed. This is a very important concept to understand. So let's dive into it.
Creating a queryset
Let's play around with just the User model just to get a feel for querysets.
- Get all users
from .models import User
users = User.objects.all()
- Get a single user
from .models import User
user = User.objects.get(id=1)
- Okay so we gave the
get()method theidof the user we want to get. But what if we want to get the user by email? We can do that too. Better yet, what if we want to get the user through a mixture of fields? It's possible.
from .models import User
user = User.objects.get(
first_name='John',
last_name='Doe',
created_at__year=2020,
)
Filtering
We could only have limited use of get() if we had to get a single user. But what if we want to get multiple users? We can do that too.
To get more fancier and chain different filters, we can use the filter() method.
from .models import User
users = User.objects.filter(
first_name='John',
last_name='Doe',
created_at__year=2020,
)
Ordering
We can order the querysets. Ordering is done by passing the field name to the order_by() method.
from .models import User
users = User.objects.order_by('first_name')
Limiting
We can limit the querysets. Limiting is done by passing the number of items to the all() method. Most often done with slicing.
from .models import User
users = User.objects.all()[:5]
Counting
We can count the querysets. Counting is done by calling the count() method. This is very useful when we want to get the number
of items in a queryset.
from .models import User
users = User.objects.count()
Use Q objects
In django we can use Q objects to combine filters. Let's see how we can do that.
from django.db.models import Q
# Find all users who have either 'John' as first name or 'Doe' as last name
users = User.objects.filter(Q(first_name='John') | Q(last_name='Doe'))
# Find all users who have 'John' as first name and 'Doe' as last name
users = User.objects.filter(Q(first_name='John') & Q(last_name='Doe'))
# Find all users who have last name 'Doe' but not 'John' as first name
users = User.objects.filter(Q(last_name='Doe') & ~Q(first_name='John'))
# Find all users who have last name 'Doe' or first name 'John' but not both
users = User.objects.filter(Q(last_name='Doe') | Q(first_name='John')).exclude(first_name='John', last_name='Doe')
Use F objects
In django we can use F objects to compare fields.
from django.db.models import F
# Find all users whose first name is the same as their last name
users = User.objects.filter(first_name=F('last_name'))
# Find all users whose age is greater than the age of their manager
users = User.objects.filter(age__gt=F('manager__age'))
# Find all users whose age is at least twice the age of their manager
users = User.objects.filter(age__gte=F('manager__age')*2)
# Find all users whose birth date is before their registration date
users = User.objects.filter(birth_date__lt=F('registration_date'))
# Find all users whose last login date is more recent than their registration date
users = User.objects.filter(last_login__gt=F('registration_date'))
Use Q objects and F objects together
We can also use Q objects and F objects together. In very complex queries, this is very useful.
from django.db.models import Q, F
# Find all users whose first name is the same as their last name and their age is greater than 18
users = User.objects.filter(Q(first_name=F('last_name')) & Q(age__gt=18))
Reverse relationships
In django it's pretty straightforward to get objects from parent to child. But what if we want to get objects from child to parent? There is a way to accomplish that.
Let's use the User model and the SocialMediaAccount model to get objects from child to parent.
from .models import User, SocialMediaAccount
# Get all social media accounts of a user
user = User.objects.get(id=1)
social_media_accounts = user.social_media_accounts.all()
What if we want to get all users of a social media account? There is a method to access attributes of the a parent object from a child object.
Let's consider the example of Building and Room models. A building can have many rooms. But a room can only have one building.
from .models import Building, Room
# Get all rooms of a building
building = Building.objects.get(id=1)
rooms = building.room_set.all()
# Get the building of a room
room = Room.objects.get(id=1)
building = room.building
- But if the relationship is a ManyToManyField, then we can use
throughto get the related objects, or we can userelated_nameto get the related objects.
Let's consider the example of User and Group models. A user can be in many groups. And a group can have many users.
from .models import User, Group
users = User.objects.filter(name='John', user_groups=g.id)
- Here we are using
user_groupsas therelated_nameof theManyToManyFieldin theUsermodel.
Note: If you want to get the related objects through a ManyToManyField, then you can use
throughto get the related objects, or you can userelated_nameto get the related objects.
Templates
In django we can use templates to render dynamic content. They are very powerful and easy to use. The syntax is very similar to HTML. It's also called Django Template Language (DTL) it's pretty similar to Jinja2.
Let's go through set up and some basic syntax.
-
First we need to create a template file. Let's create a
templatesfolder in the root of our project. Then create ausersfolder inside thetemplatesfolder. Then create aindex.htmlfile inside theusersfolder. -
Then we need to add the
TEMPLATESsetting in thesettings.pyfile.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Note: We need to add the
DIRSsetting to tell django where to look for the templates.
- To make use of the templates that we create, we need to create a view. Let's create a
views.pyfile in theusersfolder.
from django.shortcuts import render
from .models import User
def index(request):
users = User.objects.all()
return render(request, 'users/index.html', {'users': users})
- Then in the
urls.pyfile of theusersapp, we need to add theindexview.
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
- In the
index.htmlfile, we can use theusersvariable that we passed to the template.
{% for user in users %}
<p>{{ user.first_name }} {{ user.last_name }}</p>
{% endfor %}
Template tags
In django we can use template tags to do some logic in the template. I won't be covering all the template tags, just the ones that is commonly used.
iftag
{% if user.age > 18 %}
<p>{{ user.first_name }} {{ user.last_name }} is an adult</p>
{% else %}
<p>{{ user.first_name }} {{ user.last_name }} is a minor</p>
{% endif %}
fortag
{% for user in users %}
<p>{{ user.first_name }} {{ user.last_name }}</p>
{% endfor %}
urltag
<a href="{% url 'index' %}">Home</a>
Note: We can use the
urltag to get the url of a view. We need to pass the name of the view as the argument.
statictag
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
Note: We can use the
statictag to get the url of a static file. We need to pass the path of the static file as the argument. By default django looks for the static files in thestaticfolder in the root of the project.
blocktag
{% block content %}
<h1>Home</h1>
{% endblock %}
Note: We can use the
blocktag to define a block in the template. Every template that extends another template must have ablocktag. If we don't have ablocktag, then django will throw an error.
extendstag
{% extends 'base.html' %}
Pro Tip: Every template could be extended from a
base.htmlfile. This is a good practice. We can use theblocktag to override the blocks in thebase.htmlfile.
Let's demonstrate how we can use the block and extends tags. Remember block tag is used to define a block in the template,
which means when a child template extends a parent template, then the child template can override the blocks in the parent template or
add content inside that block thereby extending the parent template.
This is a great way to reuse the code, the child template is able to customize specific parts of the parent template. Without having to copy the whole template again and again.
- First we need to create a
base.htmlfile in thetemplatesfolder. Then we need to add theblocktag in thebase.htmlfile.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Base</title>
</head>
<body>
<header>
<nav>
<ul>
<li><a href="{% url 'index' %}">Home</a></li>
<li><a href="{% url 'users:index' %}">Users</a></li>
</ul>
</nav>
</header>
<main>{% block content %} {% endblock %}</main>
</body>
</html>
- Then we need to create a
index.htmlfile in theusersfolder. Then we need to add theextendstag in theindex.htmlfile.
{% extends 'base.html' %} {% block content %}
<h1>Home</h1>
{% endblock %}
Note: We need to add the
blocktag in thebase.htmlfile and theextendstag in theindex.htmlfile.
- This means the
index.htmlfile extends thebase.htmlfile. So theindex.htmlfile will have the content of thebase.htmlfile and it's own content embedded in theblocktag.
Template filters
In django we can use template filters to modify the data in the template. I won't be covering all the template filters, just the ones that is commonly used.
datefilter
<p>{{ user.created_at|date }}</p>
Note: We can use the
datefilter to format the date. We can pass the format as the argument.
timefilter
<p>{{ user.created_at|time }}</p>
Note: We can use the
timefilter to format the time. We can pass the format as the argument.
lengthfilter
<p>{{ user.first_name|length }}</p>
Note: We can use the
lengthfilter to get the length of a string.
- There are many other filters that we can use in django. We can check the documentation for more information.
Django Cache
In the world of web development, caching is a very important topic. Caching is a way to store data in a temporary storage so that we can access it faster. We need to use caching when we have data that is not changing frequently. For example, if we have a list of users, then we can cache the list of users so that we don't have to query the database every time we need the list of users. This will improve the performance of our application.
Django provides a very flexible caching system. We can use different caching backends. The integration with the caching system is very easy. We can use
the caching system in our views, templates, models, etc. Let's use Redis as the caching backend. Since Redis is an in-memory database, it is very fast and
pretty popular in the industry.
- First we need to install
django-redisandredispackages.
pip install django-redis redis
- Then we need to add the
django-redispackage to theINSTALLED_APPSin thesettings.pyfile.
INSTALLED_APPS = [
...
'django_redis',
]
- Then we need to add the
CACHESsetting in thesettings.pyfile.
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
Note: We need to add the
CACHESsetting in thesettings.pyfile. We need to pass theBACKENDandLOCATIONas the arguments.
Let's start using the caching system in our application. We will use the caching system in our index view.
- First we need to import the
cachefrom thedjango.core.cachemodule.
from django.core.cache import cache
- Then we need to add the
cachedecorator to theindexview.
@cache_page(60 * 15)
def index(request):
users = User.objects.all()
return render(request, 'users/index.html', {'users': users})
So what's happening here? We are using the cache_page decorator to cache the index view. We are passing the 60 * 15 as the argument. This means
the index view will be cached for 15 minutes. So if we access the index view within 15 minutes, then the view will be served from the cache. If we access
the index view after 15 minutes, then the view will be served from the database.
- The next thing we need to do is to add the
cachetag in theindex.htmlfile.
{% load cache %}
- Then we need to add the
cachetag in theindex.htmlfile.
{% cache 60 * 15 users %}
<ul>
{% for user in users %}
<li>{{ user.first_name }} {{ user.last_name }}</li>
{% endfor %}
</ul>
{% endcache %}
So what's happening here? We are using the cache tag to cache the users queryset. We are passing the 60 * 15 as the argument. This means
the users queryset will be cached for 15 minutes. So if we access the index view within 15 minutes,
then the users queryset will be served from the cache. If we access the index view after 15 minutes, then the users queryset will
be served from the database.
NOTE: the purpose of caching in template and view is different. In view, we are caching so that we don't recall the database every time we access the view. In template, we are caching so that we don't recall the database every time we access the template, only if the data is not altered.
Django Pagination
Django provides a very easy way to paginate the data. We can use the Paginator class to paginate the data. Let's see how we can use the Paginator class
to paginate the data.
- First we need to import the
Paginatorclass from thedjango.core.paginatormodule.
from django.core.paginator import Paginator
- Then we need to create a
Paginatorobject and pass theusersqueryset and theper_pageas the arguments.
paginator = Paginator(users, 10)
- Then we need to get the
pagenumber from therequest.GETdictionary.
page = request.GET.get('page')
- Then we need to get the
pageobject from thepaginatorobject.
page_obj = paginator.get_page(page)
- Then we need to pass the
page_objqueryset to therenderfunction.
return render(request, 'users/index.html', {'page_obj': page_obj})
- Then we need to add the
page_objto theindex.htmlfile.
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %} {% for page in page_obj.paginator.page_range %}
<a href="?page={{ page }}">{{ page }}</a>
{% endfor %} {% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next</a>
{% endif %}
- Then we need to add the
page_objto theindex.htmlfile.
{% for user in page_obj %}
<li>{{ user.first_name }} {{ user.last_name }}</li>
{% endfor %}
Django Filtersets
Django provides a very easy way to filter the data. We can use the FilterSet class to filter the data. Let's see how we can use the FilterSet class.
This acts more like the detailed search functionality. We can filter the data based on the fields.
- First we need to install the
django-filterpackage.
pip install django-filter
- Then we need to add the
django-filterpackage to theINSTALLED_APPSin thesettings.pyfile.
INSTALLED_APPS = [
...
'django_filters',
]
- Then we need to create a
UserFilterclass and inherit theFilterSetclass.
from django_filters import FilterSet
class UserFilter(FilterSet):
class Meta:
model = User
fields = ['first_name', 'last_name']
- Then we need to add the
UserFilterclass to theindexview.
def index(request):
users = User.objects.all()
user_filter = UserFilter(request.GET, queryset=users)
return render(request, 'users/index.html', {'user_filter': user_filter})
- Then we need to add the
user_filterto theindex.htmlfile.
<form action="" method="GET">
{{ user_filter.form }}
<button type="submit">Filter</button>
</form>
- That is it. Now we can filter the data based on the fields.
Conclusion
In this post, I have covered some important and useful features of Django, like Django forms, formsets, Django caching, Django pagination, and Django filtersets. I hope you have enjoyed this post. These are the features I have used throughout my Django projects. I only provided simple examples to get an idea of how these features work. There are other features like Django signal, messages, logging, etc. When I get to use these features, I will write a post about them.