djangodjango-context

Django 'context' for function-based and class-based views


Help me understand how to use Django's context--Is the issue related to the use of context in function-based vs class-based views:

I have created two views (index and post_list) and respective templates (following the Assessment portion of the Mozilla Django Tutorial). The code for index works, but identical code for post_list doesn't. Why is that?

view #1

def index(request):
    post_list = Post.objects.all()
    num_posts = Post.objects.all().count()
    num_comments = Comment.objects.all().count()
    num_authors = Author.objects.count()
    num_commenters = Commenter.objects.count()        

context = {
        'num_posts': num_posts,
        'num_comments': num_comments,
        'num_authors': num_authors,
        'num_commenters': num_commenters,
        'post_list' : post_list,
    }
return render(request, 'index.html', context=context)

template #1 --Works:

{% block content %}
 <h1>Index:</h1>
This blog has a total of {{num_posts}} posts by {{ num_authors}} authors.

{% endblock %}

view #2

class PostListView(generic.ListView):
    model = Post
    post_list = Post.objects.all()
    num_posts = Post.objects.all().count()
    num_authors = Author.objects.count()

    template_name = 'blog/post_list.html'

    context = {
        'num_posts': num_posts,
        #'num_authors': num_authors,     # Removed b/c it doesn't work
        'post_list' : post_list,
    }

    def get_context_data(self, **kwargs):
        context = super(PostListView, self).get_context_data(**kwargs)
        context['num_authors'] = Author.objects.count() # But this works!
        return context #edited, this line was left out in the original post
 
 

template#2 - not totally working:

{% block content %}
<h1>All Posts:</h1>

This blog has a total of {{num_posts}} posts by {{ num_authors}} authors.

{% endblock %}

Solution

  • Your definition of the get_context_data method does not update all the variables you expect to be using within your template. For instance, the context class variable is not the same thing as the context variable you are returning inside the get_context_data method. Therefore, the only variable to which you have access in the template is num_authors. To make sure you have all the needed variables within your template, you need to edit get_context_data to update the context with the dictionary defined at the class level:

    class PostListView(generic.ListView):
        model = Post
        post_list = Post.objects.all()
        num_posts = Post.objects.all().count()
        num_authors = Author.objects.count()
        template_name = 'blog/post_list.html'
        context_vars = {
            'num_posts': num_posts,
            'num_authors': num_authors,
            'post_list' : post_list,
        }
    
        def get_context_data(self, **kwargs):
            context = super(PostListView, self).get_context_data(**kwargs)
            context.update(PostListView.context_vars)
            return context
    

    Two main updates are made to your original code snippet: the class variable context is changed to context_vars to avoid conflicts and confusion; and the context variable within the get_context_data method is updated with the contents of context_vars. This will make sure that everything defined at the class level (i.e. PostListView.context_vars) makes it to your template.