TransWikia.com

Accessing request object in django urls.py

Stack Overflow Asked by Pax on December 11, 2021

The question is also inspired from documentation here.

I am using generic view (ListView) in Django in order to list out all the questions, current logged in user has asked. I was curious to do it without creating a View in views.py. So in urls.py I added a path like:

urlpatterns += [
    path('myqn/', login_required(views.ListView.as_view(model=models.Question, queryset=models.Question.objects.filter(user__id=request.user.id), template_name='testapp/question_list.html', context_object_name='questions')), name='myqn'),
]

Its giving me that:

NameError: name ‘request’ is not defined

I know it. Since, request object is passed by the URLConf to the View class/function. So, is there a way, I can access the user.id in this scope.

PS: The code works if I replace user__id=9. It lists out all the questions asked by user-9. 🙂

2 Answers

No, You can't.

The as_view() accepts any class attributes of a view class. In your case, the request object will not accessible from the class

class Foo(ListView):
    queryset = Question.objects.filter(user__id=request.user.id)

The above snippet you can't reference the request and hence also in your urls.py

In these kinds of complex situations, we should override the get_queryset(), as you know.

Answered by JPG on December 11, 2021

You normally do this by overriding the get_queryset method in a subclass of the ListView. So you can create a view:

# app/views.py

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.list import ListView
from app.models import Question

class QuestionListView(LoginRequiredMixin, ListView):
    model = Question
    template_name='testapp/question_list.html'
    context_object_name='questions'

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(
            user_id=self.request.user.id
        )

In the urls.py you then use the QuestionListView

# app/urls.py

from django.urls import path
from app.views import QuestionListView

urlpatterns += [
    path('myqn/', QuestionListView.as_view(), name='myqn'),
]

You can define a function or lambda expression with:

import inspect

def custom_queryset(*args, **kwargs):
    self = inspect.currentframe().f_back.f_locals['self']
    return Question.objects.filter(
        user_id=self.request.user.id
    )

urlpatterns += [
    path('myqn/', QuestionListView.as_view(get_queryset=custom_queryset), name='myqn'),
]

This is however not a good idea. First of all, it inspects the call stack, and if later the ListView is altered, it might not work anymore. Furthermore here this listview will not check if the user has logged in for example. We can not make use of the method resolution order (MRO) to make a call to a super() method.


Note: You can limit views to a class-based view to authenticated users with the LoginRequiredMixin mixin [Django-doc].

Answered by Willem Van Onsem on December 11, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP