姜戈教程。一般观点。context_object_name = '最新问题列表'

And*_*ovs 5 generics django view

我对 Django 通用视图有点困惑。如此处所示,我们正在将自定义视图转换为通用视图。虽然我了解 DetailView 和 ResultsView 中发生的情况,但我并不完全理解这是如何发生的:

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return render(request, 'polls/index.html', context)
Run Code Online (Sandbox Code Playgroud)

转换成这样:

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]
Run Code Online (Sandbox Code Playgroud)
  1. 在第一个例子中,latest_question_list = Question.objects.order_by('-pub_date')[:5]
  2. 但在第二个例子中,什么latest_question_list变量等于这里?我们甚至还没有定义它..

有人可以解释一下吗?

Wil*_*sem 5

幕后ListView执行大量操作来创建上下文并将其传递给渲染引擎。我们可以通过Classy Class-Based Views来看看实现。

本质上,当您触发此类基于类的视图时,您将根据 HTTP 方法触发get(..)post(..)等方法。

get(..)方法由类定义BaseListView,定义为:

def get(self, request, *args, **kwargs):
    self.object_list = self.get_queryset()
    allow_empty = self.get_allow_empty()
    if not allow_empty:
        # When pagination is enabled and object_list is a queryset,
        # it's better to do a cheap query than to load the unpaginated
        # queryset in memory.
        if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
            is_empty = not self.object_list.exists()
        else:
            is_empty = not self.object_list
        if is_empty:
            raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % {
                'class_name': self.__class__.__name__,
            })
    context = self.get_context_data()
    return self.render_to_response(context)
Run Code Online (Sandbox Code Playgroud)

重要的是我们首先得到get_queryset()to的结果self.objects_list,然后用 构造一个上下文self.get_context_data()。然后我们进行调用,self.render_to_response(..)基本上将使用指定的模板,并使用给定的context.

get_context数据有两个父级和一个实现。最基本的(继承层次结构中最高的)是 的函数ContextMixin,但是这个函数没有做太多事情:

def get_context_data(self, **kwargs):
    kwargs.setdefault('view', self)
    if self.extra_context is not None:
        kwargs.update(self.extra_context)
    return kwargs
Run Code Online (Sandbox Code Playgroud)

它只是采用由关键字参数构造的字典(如果没有关键字参数则为空,这里就是这种情况),并添加一个'view'与 关联的额外键self。它还可以添加可以在 中定义的额外键值对self.extra_context,但我们可以在这里忽略它。

最有趣的逻辑是在MultipleObjectMixin

def get_context_data(self, *, object_list=None, **kwargs):
    """Get the context for this view."""
    queryset = object_list if object_list is not None else self.object_list
    page_size = self.get_paginate_by(queryset)
    context_object_name = self.get_context_object_name(queryset)
    if page_size:
        paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
        context = {
            'paginator': paginator,
            'page_obj': page,
            'is_paginated': is_paginated,
            'object_list': queryset
        }
    else:
        context = {
            'paginator': None,
            'page_obj': None,
            'is_paginated': False,
            'object_list': queryset
        }
    if context_object_name is not None:
        context[context_object_name] = queryset
    context.update(kwargs)
    return super().get_context_data(**context)
Run Code Online (Sandbox Code Playgroud)

这里发生的事情是self.object_list,我们首先将我们首先使用结果设置的变量分配self.get_queryset给名为 的局部变量queryset。然后我们将对其进行分页queryset,但这与您的问题不太相关。

然后我们通过调用获取名称self.get_context_object_name(queryset)。默认情况下,其实现方式为:

def get_context_object_name(self, object_list):
    """Get the name of the item to be used in the context."""
    if self.context_object_name:
        return self.context_object_name
    elif hasattr(object_list, 'model'):
        return '%s_list' % object_list.model._meta.model_name
    else:
        return None
Run Code Online (Sandbox Code Playgroud)

因此,如果您已经设置了该context_object_name属性,就像您所做的那样,那么它只会返回该名称。因此我们可以得出结论,在get_context_data(..), 方法中,context_object_name将会具有您在此处提供的名称'latest_question_list'

然后我们继续处理 中的代码get_context_data(..):我们构造一个字典,并在底部检查是否context_object_name不是None。如果是这种情况,我们将queryset与该键相关联(因此此处与'latest_question_list')。最终,当构建正确的上下文字典时,我们使用super()构建的上下文进行调用**kwargs,正如我们之前讨论的,ContextMixin, 将简单地返回该字典,并进行非常小的更改。

因此,最后context将具有与 关联的列表名称(此处为'latest_question_list'queryset,并且它将使用该上下文数据呈现模板。