ListView in Django

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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *