SingleObjectMixin with ListView - querysets

I’m a bit confused about this code:
(From: Using mixins with class-based views | Django documentation | Django)

from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher

class PublisherDetailView(SingleObjectMixin, ListView):
    paginate_by = 2
    template_name = "books/publisher_detail.html"

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=Publisher.objects.all())
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['publisher'] = self.object
        return context

    def get_queryset(self):
        return self.object.book_set.all()

The text after it explains:
Notice how we set self.object within get() so we can use it again later in get_context_data() and get_queryset(). If you don’t set template_name, the template will default to the normal ListView choice, which in this case would be "books/book_list.html" because it’s a list of books; ListView knows nothing about SingleObjectMixin, so it doesn’t have any clue this view is anything to do with a Publisher.

So ListView knows nothing about a Publisher class and the template name must be altered because “it’s a list of books”. So I have a few questions:

  1. How is it a list of books? All methods seem to work based on a queryset of Publisher, even the third one, get_queryset(), which returns the list of books but through the queryset from get();
  2. Where does this class get to infer the model? At the very last method, the one that returns a queryset, however, again, based on an object ‘grabbed’ from a queryset of another object(Publisher)?
  3. Does the order in which parent classes are provided influence who gets to perform which method? Both SingleObjectMixin and ListView have the methods defined above, so who gets to execute what?

You’re on the right track. Let’s break this down:

self.object is a reference to a Publisher.
self.object.book_set is a reference to a Manager.

  • What is it a Manager for?
    • It’s for all the books that are related to the Publisher.
      Therefore - self.object.book_set.all() is the queryset returning all books related to the Publisher.
      Functionally, it’s no different than Book.objects.filter(publisher=publisher_id)

The get method of ListView has the line:
self.object_list = self.get_queryset()

See get_template_names

See the Python topic “Method Resolution Order” among others. (A search will find many blogs explaining this topic.)

Also, two resources I’ve found extremely useful for understanding the generic CBVs are:

1 Like