Django : Several paths, one ListView, different templates?

Viewed 163

Please help me. I want to have multiple path in urls.py (lets say a, and b). But I want to ONLY have one ListView, and this ListView need to channel me to different html file when I access the url (a.html when access 'a/', b.html when access 'b/').

Currently I use different ListView for each path (aListView and bListView), even though the model is the same. But it seems that it violate the Don't Repeat Yourself rule. And the code looks bad.

So the question is how can I define several different templates in one ListView?

Below is my current mind map. Thank you

My mind route

2 Answers

Here is an example of how you can define multiple paths that points to one ListView within multiple templates:

Let's suppose my app name is example and my project name is test_project; my setup is like this:

test_project/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    ...,  # my project urls
    path('', include('example.urls'))
]

example/urls.py

from django.urls import path
from example import views

app_name = 'example'
urlpatterns = [
    path('a/', views.GenericListView.as_view(), name='a-url'),
    path('b/', views.GenericListView.as_view(), name='b-url')
]

templates/a.html

This is A file

templates/b.html

This is B file

example/views.py

from django.views.generic.list import ListView
from django.urls import reverse


class GenericListView(ListView):
    a_template = 'a.html'
    b_template = 'b.html'

    def get_template_names(self, *args, **kwargs):
        # Check if the request path is the path for a-url in example app
        if self.request.path == reverse('example:a-url'):
            return [self.a_template]  # Return a list that contains "a.html" template name
        return [self.b_template]  # else return "b.html" template name

    def get_queryset(self, **kwargs):
        # For this example i'm returning [] as queryset for both a/ and b/ routes
        if self.request.path == reverse('example:a-url'):
            return []  # Return whatever queryset for a/ route
        return []  # Return whatever queryset for b/ route

For more informations you can visit ListView: get_template_names() Documentation

It seems to me that having 2 separate ListViews is the right approach in your situation. You have 2 different URLs and 2 different templates, so you have 2 different views. I don't think that it violates DRY principles because the common logic is abstracted by the reusable ListView class.

Related