Django 的 "request" 不是只有在显式调用时才有效吗?

Doesn't Django's "request" only work when explicitly called?

那是我的假设。但也有像 这样的例子,其中:

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

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.object is None:
            return HttpResponseRedirect(reverse('blog'))

        count_visits = None
        unique_views = set()

        if self.request.user.is_authenticated:
            post_views = PostView.objects.filter(post=self.object)
            count_visits = post_views.count()
            for post_view in post_views:
                unique_views.add(post_view.ip)

我尝试使用上面的代码,但出现错误 name 'request' is not defined。我的代码(下面)搞砸了,但我想了解如何明确 request 以便基于 class 的视图上的表单可以工作(这是另一个 post):

class PostDetailView(generic.DetailView):
    model = Post
    context_object_name = 'post'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        if self.object is None:
            return HttpResponseRedirect(reverse('/'))

        if self.request.user.is_authenticated:
            comment_form = CommentForm(request.POST)
            comment_form.save()

回溯:

Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/blog/2/

Django Version: 3.2.5
Python Version: 3.9.1
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'blog.apps.BlogConfig',
 'accounts.apps.AccountsConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/detail.py", line 107, in get
    context = self.get_context_data(object=self.object)
  File "/Users/user/dev/assess_new/blog/views.py", line 97, in get_context_data
    post = get_object_or_404(Post, pk=self.id)

Exception Type: AttributeError at /blog/2/
Exception Value: 'PostDetailView' object has no attribute 'id' 

我注释掉了第 97 行并得到了这个(这促使我首先 post 这个问题):

name 'request' is not defined

Traceback (most recent call last):
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "/Users/user/dev/assess_new/venv/lib/python3.9/site-packages/django/views/generic/detail.py", line 107, in get
    context = self.get_context_data(object=self.object)
  File "/Users/user/dev/assess_new/blog/views.py", line 111, in get_context_data
    comment_form = CommentForm(request.POST)

Exception Type: NameError at /blog/2/
Exception Value: name 'request' is not defined

您不能 return get_context_data 中的 HTTP 响应对象。 Django 期望这个 return 是一个字典,而不是 HttpResponseRedirect 例如。

然而,如果没有这样的对象,您可以处理重定向,例如将其包装在 try-except 对象中:

from django.core.exceptions import <strong>ObjectDoesNotExist</strong>
from django.shortcuts import redirect

class PostDetailView(generic.DetailView):
    model = Post
    context_object_name = 'post'

    def get(self, request, *args, **kwargs):
        try:
            self.object = self.get_object()
        except ObjectDoesNotExist:
            return redirect('blog')
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        count_visits = None
        unique_views = set()
        if self.request.user.is_authenticated:
            post_views = PostView.objects.filter(post=self.object)
            count_visits = post_views.count()
            for post_view in post_views:
                unique_views.add(post_view.ip)
        context.update(count_visits=count_visits, unique_views=unique_views)
        return <strong>context</strong>

get_context_data方法中,你应该return一个字典,你可以向context添加额外的项目,但最终它return是context.例如使用 context.update(count_visits=count_visits, unique_views=unique_views) 调用。