2

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 %}
YCode
  • 1,192
  • 1
  • 12
  • 28
  • Your `get_context_data` method does not seem to be returning the `context` dictionary. When invoked at runtime, it's returning `None`. Add `return context` at the bottom of the method definition. – Abdou Jul 12 '21 at 17:27
  • @abdou I l accidentally left out the line `return context` for `get_context_data`, but it was in the code--doesn't help though. – YCode Jul 12 '21 at 17:30
  • Other than looking at the code, it's hard to spot what's not working. Are you getting errors or is the template not rendering with the proper values? – Abdou Jul 12 '21 at 17:34
  • What is happening on the second case? – Bernardo Duarte Jul 12 '21 at 18:36
  • @BernardoDuarte In the second case, the value doesn't get rendered at all. – YCode Jul 12 '21 at 18:59
  • @Abdou No error, but the values don't show up. – YCode Jul 12 '21 at 18:59
  • Another block of code w similar issues: The `context` block doesn't get rendered. But `context['authors'] = Author.objects.all()` works. `authors = Author.objects.all() num_authors=Author.objects.count() context = { 'authors': authors, 'num_authors': num_authors, } def get_context_data(self, **kwargs): context = super(AuthorListView, self).get_context_data(**kwargs) context['num_authors'] = Author.objects.count() context['authors'] = Author.objects.all()
    return context`
    – YCode Jul 12 '21 at 19:00

1 Answers1

2

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.

Abdou
  • 12,931
  • 4
  • 39
  • 42
  • 2
    Ahhh! Thanks for the explanation--it clears up my confusion over how `context` gets passed into templates. I've done the tutorial several times and this is one of the areas that always trip me up. As with new learners, I find it hard to ask the right question. Appreciate your insight! – YCode Jul 13 '21 at 00:00