18

I am using Django's class based generic views in a blog application. One of my views displays a list of posts that have a certain tag. I can write this view as a ListView of posts, filtered by tag. Or I can write this view as a DetailView of the tag, and add the relevant posts to the context.

Is one way more proper -- or Pythonic -- than the other?

The ListView approach seems more semantic, because what I want is a list of posts, but it's also slightly more complex. It requires that I overwrite two methods. The DetailView approach only requires me to overwrite one method.

class PostTagView(ListView):
    """Display all blog posts with a given tag."""
    queryset = Post.objects.published()

    def get_context_data(self, **kwargs):
        context = super(PostTagView, self).get_context_data(**kwargs)
        context['tag'] = get_object_or_404(Tag, slug=self.kwargs['slug'])
        return context

    def get_queryset(self, **kwargs):
        queryset = super(PostTagView, self).get_queryset()
        return queryset.filter(tags__slug=self.kwargs['slug'])


class TagDetailView(DetailView):
    """Display all blog posts with a given tag."""
    model = Tag

    def get_context_data(self, **kwargs):
        context = super(TagDetailView, self).get_context_data(**kwargs)
        context['object_list'] = Post.objects.published().filter(tags__slug=self.kwargs['slug'])
        return context
user1272534
  • 991
  • 2
  • 11
  • 17

4 Answers4

12

As a rule of thumb, look at the parameters in the URL. If you're using a slug of a Tag then you're most likely dealing with a DetailView and not a ListView.

In this case, the second approach uses less code and it is more elegant. However, it also depends on what you're going to do with the view later on. If you're going to add forms to edit the posts, it might make sense to use a ListView instead. But there's no technical reason to prefer one over the other, it's just that you might end up writing more code in one approach than in the other.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
  • 1
    Matching it with the URL parameters makes sense. – user1272534 Mar 19 '12 at 23:31
  • Great answer. Now how would you paginate it? Using the list view, it's trivial. Doing it as a detail view, I get lost :( – Dan Gayle Dec 26 '13 at 23:44
  • 2
    @DanGayle: a `DetailView` should not be paginated, it's intended to be used with one object only. – Simeon Visser Dec 27 '13 at 00:13
  • Except for the logic above in this answer. I'm looking at the detail view of a tag that just so happens to have a huge list of posts that I want paginated. I could easily have written it as a listview, but then I would have had to add the tag *back* to the context. Which seems backwards. – Dan Gayle Dec 27 '13 at 00:29
  • Well, either way you'll be writing a lot of code as it doesn't fit in either of the views. So adding pagination to a DetailView seems more logical, but I agree it's not ideal. – Simeon Visser Dec 27 '13 at 02:24
  • 1
    @DanGayle you can add [`MultipleObjectMixin`](http://ccbv.co.uk/projects/Django/1.7/django.views.generic.list/MultipleObjectMixin/) to your `DetailView`, which allows you to reuse pagination. You just need to ensure `self.object_list` is set to the queryset of filtered objects you want to paginate. – julen Jan 18 '15 at 17:53
  • maybe a noob question what is slug – Kanishk Tanwar Jun 12 '18 at 15:50
4

Both ListView and DetailView are not the same technically, For example you cannot give the path for a DetailView like the below in urls.py,

path('schools_detail/',views.SchoolDetailView.as_view(),name = "detail"),

This will give the below error,

Generic detail view SchoolDetailView must be called with either an object pk or a slug in the URLconf.

This means that if we have a table called Student and another table called School, we can use the ListView to list all the schools like below,

path('list/',views.SchoolListView.as_view(),name = "list"),

And if we want to list the Schools details for individual school when we click the school icon, then we can use the primary key of the School which Django creates internally and capture it in the url pattern, in my case the url pattern would be "list/{{school.id}}" so to capture this we have to give the path like below for DetailsView,

path('list/<int:pk>/',views.SchoolDetailView.as_view(),name = "detail"),

So Bottom line is you can use the ListView as a normal view for most of the cases, if you want to access another View but only a particular detail in that View which refers with a primary key then you can use DetailsView(the url pattern for the DetailsView will be generated by giving the primary key info in the url, without primary key in the url it wont work since it wont take all the info instead it will only take the info related to the primary key in the url)

Arunkumar Arjunan
  • 375
  • 1
  • 3
  • 12
2

Interesting question. Unfortunately, the answer is not quite so interesting: whichever makes the most sense for you and your app. Arguments could be made equally for either approach, so it's really just a judgement call.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
0

The usecase for class based generic views are perfectly described in article:

https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views

In above mentioned article, you'd be able to know when/why and how to use ListView/DetailView along with simple examples.

Talat Parwez
  • 129
  • 4