A ListView is a view (logic) that allows you to see numerous instances of the same table in the database. In List View – Function-based Views Django, one of the core fundamentals is the ListView. Views can be implemented as Python objects instead of functions using class-based views. They do not replace function-based views, but they do have several advantages and differences when compared to them:
- Different methods, rather than conditional branching, can organize code relevant to various HTTP methods (GET, POST, etc.).
- Mixins (multiple inheritances) and other object-oriented approaches can fold code into reusable components.
- Views based on classes are easier to manage and maintain than views based on functions. You can transform a function-based view with many lines of code into a class-based view with only a few lines of code.
- Object-Oriented Programming (OOP) comes into play here.
Let’s create a view with the base view View, change it to TemplateView, then ListView. We hope to demonstrate that a ListView would save us several lines of code while also providing greater separation of concerns in the application.
ListViews in Django — Function-Based Views
Using an example, demonstrate how to construct and operate a List view. Consider a project called CodeunderscordListView, which has a CodeApp. In this case, let’s first establish a model from which we’ll create instances through our view after creating the project and an app.
In the CodeApp/models.py file,
# importing the standard Django Model from the built-in library from django.db import models # declaration of a new model with a name "CodeModel" class CodeModel(models.Model): # model's fields title = models.CharField(max_length = 200) description = models.TextField() # renaming model instances with their title name def __str__(self): return self.title
After creating this model, we’ll need to run two commands to establish a database for it.
Python manage.py makemigrations Python manage.py migrate
Now let’s use the shell to build some instances of this model by running bash form as shown below.
python manage.py shell
Enter the commands below.
from CodeApp.models import CodeModel CodeModel.objects.create(title="first title",description=" first description").save() CodeModel.objects.create(title="second title",description="second description").save() CodeModel.objects.create(title="second title",description="second description").save()
Everything is now ready for the back end. You can confirm this by checking http://localhost:8000/admin/code/codemodel/ to ensure if instances have been created.
Vanilla View
We want to create a page that displays all of the items in the CodeModel in the database. The following is an example of a view:
class CodeListView(View): def get(self, request, *args, **kwargs): codes = CodeModel.objects.all() context = {'codes': codes} return render(request, "codemodel_list.html", context=context)
Subclassing the TemplateView
class CodeListView(TemplateView): template_name = 'codemodel_list.html' def get_context_data(self, *args, **kwargs): context = super(CodeListView, self).get_context_data(*args, **kwargs) context['codes'] = CodeModel.objects.all() return context
When utilizing TemplateView, we don’t have to give a get() implementation or worry about render(). TemplateView takes care of everything. To add context to the template, we merely needed a get_context_data() implementation.
Subclassing the ListView
from django.views.generic.list import ListView class CodeListView(ListView): template_name = 'codemodel_list.html' queryset = CodeModel.objects.all() context_object_name = 'codes'
ListView reduces the amount of boilerplate in TemplateView. We didn’t have to worry about implementing get_context_data() with ListView. ListView establishes the ‘codes’ context variable and delivers it to the template. In addition, you can also add filtering to ListView.queryset as follows:
class CodeListView(ListView): template_name = 'codemodel_list.html' queryset = CodeModel.objects.filter(name='Advanced Programming in Python') context_object_name = 'codes'
We would have had to add numerous lines of code to TemplateView or the vanilla View implementation if we desired pagination. We don’t have to write a pagination code because ListView provides it free.
ListView subclasses can have pagination enabled by setting the paginate_by variable below.
class CodeListView(ListView): template_name = 'codemodel_list.html' queryset = CodeModel.objects.all() context_object_name = 'codes' paginate_by = 15
Following that, /codemodel-list/?page=1 returns the first 15 books. On the other hand, /codemodel-list/?page=2 returns the following 15 books, and so on.
If your queryset on your list page doesn’t require any filtering and works with your model’s.all() method, you can use a model attribute on the CodeListView instead of queryset.
# Adding to the ListView configuration class CodeListView(ListView): template_name = 'codemodel_list.html' model = CodeModel context_object_name = 'codes' paginate_by = 15
The ordering attribute on View can add an order to your queryset. Assume you want the codes on the page sorted in ascending order by their creation date. What you can do is:
class CodeListView(ListView): template_name = 'codemodel_list.html' model = CodeModel context_object_name = 'codes' paginate_by = 15 ordering = ['-created']
You can order by several qualities because the order is a list. In addition, you can forgo adding model or queryset to the list view and instead supply a get_queryset() implementation if you want to filter the queryset differently for different web requests.
class CodeListView(ListView): template_name = 'codemodel_list.html' context_object_name = 'CodeModel' paginate_by = 15 ordering = ['-created'] def get_queryset(self): return CodeModel.objects.filter(created_by=self.request.user)
You can instead avoid using the template_name attribute. Because ListView’s default behavior is to utilize a template called / _list.html. As a result, you can modify the appearance of your CodeListView to something like this:
class CodeListView(ListView): model = CodeModel context_object_name = 'codes' paginate_by = 15
Your template code, however, should be under CodeApp/codemodel_list.html. It implies your CodeModel model is a collection of app CodeApp. If the CodeModel model is used in an app, such as entitites, the template code is placed in entities/codemodel_list.html.
You can also avoid using context_object_name. Since ListView’s default behavior is to fill the template with the context name object_list. Thus, you can modify the appearance of your CodeListView to something like this:
class CodeListView(ListView): model = CodeModel paginate_by = 15
Essentially, a ListView saves you time by removing boilerplate code such as:
- Provision of a GET() implementation
- Creating an ordered queryset
- It delivers pagination code that is encapsulated. In fact, it would have been easy to add another 10 lines of code if we had implemented pagination code in the vanilla view.
- providing a reasonable context for the template
- Creating and returning a HttpResponse() or HttpResponse() subclass object.
A ListView must have a model, queryset, or get_queryset() implementation at a minimum. Every other component has a reasonable default value.
ListView in Action
Class-Based Views take care of everything from start to finish. Indicate the model to establish a ListView for, and Class-based ListView will automatically look for a template in app name/modelname_list.html.
It’s CodeApp/templates/code/codemodel_list.html in our case. Let’s start by making our class-based view. In the CodeApp/views.py file,
from django.views.generic.list import ListView from .models import CodeModel class CodeList(ListView): # specify the model for list view model = CodeModel
Now create a URL path to map the view. In CodeApp/urls.py,
from django.urls import path # importing views from views..py from .views import CodeList urlpatterns = [ path('', CodeList.as_view()), ]
In templates/CodeApp/codemodel_list.html, make a template.
<ul> <!-- Iterate over object_list --> {% for object in object_list %} <!-- Display Objects --> <li>{{ object.title }}</li> <li>{{ object.description }}</li> <hr/> <!-- If object_list is empty --> {% empty %} <li>No objects yet.</li> {% endfor %} </ul>
When done, you can check what is there on http://localhost:8000/. The latter should be done after firing up your server and doing the prerequisites covered earlier to create database tables.
Manipulating the Queryset In ListView
By default, ListView displays all table instances in the order generated. The get_queryset method is overridden if the sequence or order of these instances is changed.
In the CodeApp/views.py file,
from django.views.generic.list import ListView from .models import CodeModel class CodeList(ListView): # specifying the list view's model model = CodeModel def get_queryset(self, *args, **kwargs): qs = super(CodeList, self).get_queryset(*args, **kwargs) qs = qs.order_by("-id") return qs
Check to ascertain if the order of the instances has been changed. It allows you to change the entire queryset in whatever way you choose.
Conclusion
Django includes several generic views based on classes to help with everyday tasks. ListView is one of them. TemplateView is the most basic class-based generic view. However, when you wish to exhibit a list of objects on an HTML page, you should use the ListView.
When your page has forms and creates or updates objects, you should not use a ListView. FormView, CreateView, and UpdateView are better for working with forms, object creation, and object updates. TemplateView can do everything the ListView can; however, the ListView has the advantage of not requiring as much boilerplate code as TemplateView would.