Search code examples
djangolistviewdjango-queryset

unable to get kwargs from get_queryset of ListView


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>

Solution

  • 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.