Django教程。通用视图。 context_object_name ='latest_question_list'

时间:2019-05-10 16:54:20

标签: django generics view

我对Django通用视图有些困惑。如here所示,我们正在将自定义视图转换为通用视图。虽然我了解了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)

转换为此:

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]
  1. 在第一个示例中,latest_question_list = Question.objects.order_by('-pub_date')[:5]
  2. 但是在第二个示例中,这里的latest_question_list变量等于什么?我们甚至都没有定义它。.

任何人都可以对此有所了解吗?

3 个答案:

答案 0 :(得分:2)

幕后的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)

导入部分是,我们首先将get_queryset()的结果转换为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

它仅采用由关键字参数构建的字典(如果没有关键字参数,则为空,在这种情况下为空),并添加与'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)

这里发生的是,我们首先将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

因此,如果像您一样设置了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),并将使用该上下文数据呈现模板。

答案 1 :(得分:1)

在基于类的视图中,您使用了context_object_name = 'latest_question_list' 因此,它类似于您在基于函数的视图中使用的latest_question_list

在基于类的视图中,如果不添加context_object_name,则其值将自动object_list。 像context_object_name='object_list'之类的东西。

答案 2 :(得分:1)

已接受答案的TL; DR版本。

在后台,Django在ListView通用视图中做了很多事情。

对于这种视图:

class IndexView(generic.ListView):
      model=Question

自动生成的上下文变量为question_list。 如果要覆盖它,则必须使用context_object_name变量来设置自定义上下文变量的名称。只需设置名称即可。

然后,您必须使用get_queryset预定义函数,该函数会将其输出与context_object_name变量关联。

因此,对于变量和函数使用这些特定的名称很重要。