unable to get kwargs from get_queryset of ListView

Viewed 2687

I want to get pk, or id of each post in 'views.py' so that I can use it for filtering and getting extra data in 'get_context_data'(Eventually, I want to check access of currently logged in user to each post). When website runs, it shows error message "KeyError at /post".

What could be a problem in this?

I was trying to apply example in django's official website(https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/).
I couldn't see a significant difference between this example and mine.

views.py

class PostList(ListView):
    model = Post
    template_name = 'post/post_list.html'

    def get_queryset(self):
        self.post = get_object_or_404(Post, pk=self.kwargs['pk'])
        return Post.objects.filter(pk=self.post)

    def get_context_data(self, **kwargs):
         context = super(PostList, self).get_context_data(**kwargs)
         context['post_info'] = self.post
         context['check_access'] = Access.objects.filter(sender
         return context

post/urls.py

urlpatterns = [
   path('<int:pk>', PostList.as_view(), name='post_list'),
]

I expected to see pk or id of each post but it shows below instead:

self.post = get_object_or_404(Post, pk=self.kwargs['pk']) ...
▼ Local vars
Variable    Value
args    
()
kwargs  
{}
self    
<post.views.PostList object at 0x107ab0ba8>
1 Answers

Well the URL is missing the primary key. You have to include it, like:

urlpatterns = [
    path('<int:pk>', PostList.as_view(), name='post_list'),
]

Then you can query this with:

localhost:8000/post/123

with 123 the primary key for which you want to retrieve data.

This however does not look like a ListView [Django-doc]. A ListView should be used when you render a list of objects. This looks more like a DetailView [Django-doc].

The nice thing about a DetailView is that it even automatically filters on primary key and slug. It will automatically raise a 404 response if no such object exists.

So you likely want to use:

class PostDetailView(DetailView):
    model = Post
    context_object_name = 'post'
    template_name = 'post/post_list.html'

    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context['check_access'] = Access.objects.filter(...)
         return context

The context_object_name [Django-doc] specifies the name of the template variable for that object.

Related