A ListView
за завесами выполняет множество операций для создания контекста и передачи его в механизм визуализации.Мы можем взглянуть на реализацию через Классные представления на основе классов .
По сути, когда вы запускаете такое представление на основе классов, вы будете зависеть от HTTP.метод, вызвать метод get(..)
, post(..)
и т. д.
Метод get(..)
определяется классом BaseListView
и определяется как:
def get(self, request, *args, **kwargs):
<b>self.object_list = self.get_queryset()</b>
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__,
})
<b>context = self.get_context_data()</b>
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
Она просто берет словарь, построенный по ключевому словуarguments (пусто, если нет ключевых слов аргументов, как здесь), и он добавляет дополнительный ключ 'view'
, связанный с self
.Он также может добавлять дополнительные пары ключ-значение, которые могут быть определены в self.extra_context
, но мы можем игнорировать это здесь.
Наиболее интересная логика реализована в MultipleObjectMixin
:
def get_context_data(self, *, object_list=None, **kwargs):
"""Get the context for this view."""
<b>queryset = object_list if object_list is not None else self.object_list</b>
page_size = self.get_paginate_by(queryset)
<b>context_object_name = self.get_context_object_name(queryset)</b>
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:
<b>context[context_object_name] = queryset</b>
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:
<b>return self.context_object_name</b>
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
, и он отобразит шаблон с этими данными контекста.