继承方式
- ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView)
- MultipleObjectTemplateResponseMixin
- TemplateResponseMixin
- BaseArchiveIndexView
- BaseDateListView
- MultipleObjectMixin
- ContextMixin
- DateMixin
- View
- MultipleObjectMixin
- BaseDateListView
graph TD ArchiveIndexView[ArchiveIndexView] --> |依赖其生成模板名称的函数| MultipleObjectTemplateResponseMixin(MultipleObjectTemplateResponseMixin) ArchiveIndexView --> |依赖其数据返回函数| BaseArchiveIndexView(BaseArchiveIndexView) BaseArchiveIndexView --> |依赖其请求响应函数与数据获取| BaseDateListView(BaseDateListView) MultipleObjectTemplateResponseMixin --> |依赖其返回渲染模板的函数 | TemplateResponseMixin(TemplateResponseMixin) BaseDateListView --> |依赖其中返回的查询信息| MultipleObjectMixin(MultipleObjectMixin) BaseDateListView --> |依赖其日期转换函数| DateMixin(DateMixin) BaseDateListView --> |依赖其中初始化函数以及访问方法的调用| View(View) MultipleObjectMixin --> |依赖及重写其中的获取数据函数| ContextMixin(ContextMixin)
处理过程
url会将request对象和其他用户定义参数传入RedirectView,View父类负责执行初始化方法,将用户定义变量添加到类属性中,并调用as_view方法查找对应请求方式的处理函数(BaseDateListView中的get方法)。get方法调用BaseArchiveIndexView中重写的get_dated_items函数,获取查询集、日期列表、扩展上下文信息。后返回渲染过的模板。
使用方法
常用的参数:
- model,queryset
指定查询的模块或查询集 - date_field
指定过滤的日期字段 - context_object_name
指定返回的上下文名称 - template_name
指定需要渲染的模板文件 - date_list_period
指定度量单位,即区间
返回结果
返回查询集,指定时间区间的查询集列表,空的扩展上下文信息,并渲染模板。
代码解析
ContextMixin,MultipleObjectMixin,MultipleObjectTemplateResponseMixin,TemplateResponseMixin
参考ListView
DateMixin
主要参数
- date_field
指定用以时间过滤的字段.必须指定 - allow_future
是否允许使用未来的时间进行查询,bool值。默认为False
功能函数
- get_date_field
返回date_field,如未指定会引发ImproperlyConfigured异常 - get_allow_future
返回allow_future - uses_datetime_field
判断指定的date_filed是否真的是时间字段。返回bool值。使用cached_property装饰器以保证只进行一次计算 - _make_date_lookup_arg
将时间转换为DateTime格式,并根据settings文件添加时区。 - _make_single_date_lookup
将提供的起止时间使用 _make_date_lookup_arg 函数转换。如果指定的date_field 不是DateTimeField格式,则直接返回。
代码
class DateMixin:
"""Mixin class for views manipulating date-based data."""
date_field = None
allow_future = False
def get_date_field(self):
"""Get the name of the date field to be used to filter by."""
if self.date_field is None:
raise ImproperlyConfigured("%s.date_field is required." % self.__class__.__name__)
return self.date_field
def get_allow_future(self):
"""
Return `True` if the view should be allowed to display objects from
the future.
"""
return self.allow_future
# Note: the following three methods only work in subclasses that also
# inherit SingleObjectMixin or MultipleObjectMixin.
@cached_property
def uses_datetime_field(self):
"""
Return `True` if the date field is a `DateTimeField` and `False`
if it's a `DateField`.
"""
model = self.get_queryset().model if self.model is None else self.model
field = model._meta.get_field(self.get_date_field())
return isinstance(field, models.DateTimeField)
def _make_date_lookup_arg(self, value):
"""
Convert a date into a datetime when the date field is a DateTimeField.
When time zone support is enabled, `date` is assumed to be in the
current time zone, so that displayed items are consistent with the URL.
"""
if self.uses_datetime_field:
value = datetime.datetime.combine(value, datetime.time.min)
if settings.USE_TZ:
value = timezone.make_aware(value, timezone.get_current_timezone())
return value
def _make_single_date_lookup(self, date):
"""
Get the lookup kwargs for filtering on a single date.
If the date field is a DateTimeField, we can't just filter on
date_field=date because that doesn't take the time into account.
"""
date_field = self.get_date_field()
if self.uses_datetime_field:
since = self._make_date_lookup_arg(date)
until = self._make_date_lookup_arg(date + datetime.timedelta(days=1))
return {
'%s__gte' % date_field: since,
'%s__lt' % date_field: until,
}
else:
# Skip self._make_date_lookup_arg, it's a no-op in this branch.
return {date_field: date}
BaseDateListView
继承
继承自 MultipleObjectMixin, DateMixin, View
主要参数
- allow_empty
是否允许控的查询值 - date_list_period
查询单位(周期),默认为年(year)
功能函数
- get
允许get请求访问,并返回查询信息。调用本身的get_dated_items方法和父类MultipleObjectMixin的render_to_response方法 - get_dated_items
必须重写此函数实现自己的逻辑。需要返回格式为 [date_list,object_list,{kwagrs}] - get_ordering
返回排序方法,默认为降序 - get_dated_queryset 返回具体的查询结果。如果结果为空,且allow_empty为假,将触发404错误
- get_date_list_period 返回date_list_period
- get_date_list 返回匹配的日期列表
代码
class BaseDateListView(MultipleObjectMixin, DateMixin, View):
"""Abstract base class for date-based views displaying a list of objects."""
allow_empty = False
date_list_period = 'year'
def get(self, request, *args, **kwargs):
self.date_list, self.object_list, extra_context = self.get_dated_items()
context = self.get_context_data(
object_list=self.object_list,
date_list=self.date_list,
**extra_context
)
return self.render_to_response(context)
def get_dated_items(self):
"""Obtain the list of dates and items."""
raise NotImplementedError('A DateView must provide an implementation of get_dated_items()')
def get_ordering(self):
"""
Return the field or fields to use for ordering the queryset; use the
date field by default.
"""
return '-%s' % self.get_date_field() if self.ordering is None else self.ordering
def get_dated_queryset(self, **lookup):
"""
Get a queryset properly filtered according to `allow_future` and any
extra lookup kwargs.
"""
qs = self.get_queryset().filter(**lookup)
date_field = self.get_date_field()
allow_future = self.get_allow_future()
allow_empty = self.get_allow_empty()
paginate_by = self.get_paginate_by(qs)
if not allow_future:
now = timezone.now() if self.uses_datetime_field else timezone_today()
qs = qs.filter(**{'%s__lte' % date_field: now})
if not allow_empty:
# When pagination is enabled, it's better to do a cheap query
# than to load the unpaginated queryset in memory.
is_empty = len(qs) == 0 if paginate_by is None else not qs.exists()
if is_empty:
raise Http404(_("No %(verbose_name_plural)s available") % {
'verbose_name_plural': qs.model._meta.verbose_name_plural,
})
return qs
def get_date_list_period(self):
"""
Get the aggregation period for the list of dates: 'year', 'month', or
'day'.
"""
return self.date_list_period
def get_date_list(self, queryset, date_type=None, ordering='ASC'):
"""
Get a date list by calling `queryset.dates/datetimes()`, checking
along the way for empty lists that aren't allowed.
"""
date_field = self.get_date_field()
allow_empty = self.get_allow_empty()
if date_type is None:
date_type = self.get_date_list_period()
if self.uses_datetime_field:
date_list = queryset.datetimes(date_field, date_type, ordering)
else:
date_list = queryset.dates(date_field, date_type, ordering)
if date_list is not None and not date_list and not allow_empty:
raise Http404(
_("No %(verbose_name_plural)s available") % {
'verbose_name_plural': queryset.model._meta.verbose_name_plural,
}
)
return date_list
BaseArchiveIndexView
继承
继承自 BaseDateListView
主要参数
- context_object_name
指定了上下文的名称
功能函数
- get_dated_items
重写了父类的方法。首先获取查询集,然后获取日期列表,默认为倒序。如果没有获取到时间列表,则置空查询集。返回日期列表,查询集,空的扩展上下文 。
代码
class BaseArchiveIndexView(BaseDateListView):
"""
Base class for archives of date-based items. Requires a response mixin.
"""
context_object_name = 'latest'
def get_dated_items(self):
"""Return (date_list, items, extra_context) for this request."""
qs = self.get_dated_queryset()
date_list = self.get_date_list(qs, ordering='DESC')
if not date_list:
qs = qs.none()
return (date_list, qs, {})
ArchiveIndexView
继承
继承自MultipleObjectTemplateResponseMixin, BaseArchiveIndexView
主要参数
- template_name_suffix 指定模板后缀。此参数为MultipleObjectTemplateResponseMixin中使用。生成的默认名称为appname+modelname+后缀
代码
class ArchiveIndexView(MultipleObjectTemplateResponseMixin, BaseArchiveIndexView):
"""Top-level archive of date-based items."""
template_name_suffix = '_archive'