Search code examples
pythondjangogenericsviewdocumentation

I have a question about generic view in Django's tutorial example


In the “Writing your first Django app, part 4” of the tutorial of Django documentation, there is example of using generic view like blow ;

File name : polls/views.py

class IndexView(generic.ListView):
      template_name = "polls/index.html"
      context_object_name = "latest_question_list"

      def get_queryset(self):
        """Return the last five published questions."""
          return Question.objects.order_by("-pub_date")[:5]

class DetailView(generic.DetailView):
      model = Question
      template_name = "polls/detail.html"

class ResultsView(generic.DetailView):
      model = Question
      template_name = "polls/results.html"`

Q1 .in “class IndexView”, where is the “latest_question_list” defined? Is it the return value of “get_queryset” function? If so, how can I find the relationship between “latest_question_list”and “get_queryset” function? There is not any clue.

Q2.there is a explanation in the tutorial like so: In previous parts of the tutorial, the templates have been provided with a context that contains the question and latest_question_list context variables. For DetailView the question variable is provided automatically – since we’re using a Django model (Question), Django is able to determine an appropriate name for the context variable. However, for ListView, the automatically generated context variable is question_list. To override this we provide the context_object_name attribute, specifying that we want to use latest_question_list instead.

My question is that, it said the question variable is provided automatically for DetailVIew. what does the “question” variable mean exactly? there is not “question” variable even in the model(Question). And why does the DetailView and ListView automatically generate the variables –“question”,”question_list” ?

File name : polls/models.py

class Question(models.Model):
      question_text = models.CharField(max_length=200)
      pub_date = models.DateTimeField("date published")

      def __str__(self):
          return self.question_text
    
     def was_published_recently(self):
         return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

class Choice(models.Model):
      question = models.ForeignKey(Question, on_delete=models.CASCADE)
      choice_text = models.CharField(max_length=200)
      votes = models.IntegerField(default=0)

      def __str__(self):
          return self.choice_text

I read the Django documentation for generic view, but I couldn't find the answer.

I really appreciate your responses.


Solution

  • Short answer: the names are created in a method named get_context_object_name() and are based on the names of the models. Django does this presumably to make it easier to understand in the templates. Ex: instead of seeing object_list or object, you know it's a question_list or question.


    Q1: latest_question_list is the name that you are giving it. This name will appear and be available in the template. Since this is a ListView, the default name that shows up in the template is usually named object_list. It's simply a way of adding the list of Django objects to your context to make it easier to work with in the template (rather than calling it "object_list").

    See this amazing website for deeply understanding class-based views:

    ccbv.co.uk ListView get_context_data

    Q2: To understand this, review the DetailView methods.

    Start with the get method:

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)
    

    self.object is a single model object instance that is found by using the model and objects.all() and then filtering it down to a single model object. See the get_object() method comments for the details.

    Next, get_context_data() is where the context_object_name is added to the context.

    def get_context_data(self, **kwargs):
        """Insert the single object into the context dict."""
        context = {}
        if self.object:
            context["object"] = self.object
            context_object_name = self.get_context_object_name(self.object)
            if context_object_name:
                context[context_object_name] = self.object
        context.update(kwargs)
        return super().get_context_data(**context)
    
    def get_context_object_name(self, obj):
        """Get the name to use for the object."""
        if self.context_object_name:
            return self.context_object_name
        elif isinstance(obj, models.Model):
            return obj._meta.model_name
        else:
            return None
    

    Basically, if you defined a context_object_name at the top of your view, that name will appear in the template context. Otherwise, the object (self.object) model's name will get added to the template context. If your model is named Question, then question will be seen in the context and it will be the single question object.