SingleObjectMixin
主要功能:
-
def get_queryset(self):
返回query_set里的所有对象- 如果提供的
queryset
为空且model
不为空,返回self.model._default_manager.all()
- 提供了
queryset
,返回self.queryset.all()
- 如果提供的
-
get_object(self, queryset=None)
:根据请求url里的关键字参数pk或者slug过滤query_set来获取单一对象(obj)queryset = queryset.filter(pk=pk) 或者 queryset = queryset.filter(**{slug_field: slug}) obj = queryset.get() return obj
-
def get_context_data(self, **kwargs):
将对象(obj)其插入到渲染模板所需的上下文中self.object = self.get_object context['object'] = self.object # 或者可以自定义对象名,两者是同时存在的: context[context_object_name] = self.object
class SingleObjectMixin(ContextMixin):
"""
提供了可以操纵检索单一对象的能力
"""
model = None
queryset = None
slug_field = 'slug'
context_object_name = None
slug_url_kwarg = 'slug'
pk_url_kwarg = 'pk'
query_pk_and_slug = False
def get_object(self, queryset=None):
# 根据pk和slug查找object
# 如果自定义了queryset就使用它,这是子类需要的
# 比如DateDetailView
if queryset is None:
queryset = self.get_queryset()
# 接着试着查询pk
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
if pk is not None:
queryset = queryset.filter(pk=pk)
# 接着试着查询slug
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
# If none of those are defined, it's an error.
if pk is None and slug is None:
raise AttributeError(
"Generic detail view %s must be called with either an object "
"pk or a slug in the URLconf." % self.__class__.__name__
)
try:
# Get the single item from the filtered queryset
obj = queryset.get()
except queryset.model.DoesNotExist:
raise Http404(_("No %(verbose_name)s found matching the query") %
{'verbose_name': queryset.model._meta.verbose_name})
return obj
def get_context_data(self, **kwargs):
"""插入单一对象到上下文字典中"""
context = {}
if self.object:
context['object'] = self.object
context_object_name = self.get_context_object_name(self.object)
if context_object_name:
context[context_object_name] = self.object
context.update(kwargs)
return super().get_context_data(**context)
BaseDetailView
BaseDetailView
主要是组合SingleObjectMixin
和view
的各种方法来实现服务器处理一个获取单一对象的get请求的一般流程。
class BaseDetailView(SingleObjectMixin, View):
"""一个展示单一对象的基本视图"""
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
SingleObjectTemplateResponseMixin
SingleObjectTemplateResponseMixin主要是重写了get_template_names
方法,也就是其模板的名字是
app_label + model_name(小写) + template_name_suffix(_detail)
class SingleObjectTemplateResponseMixin(TemplateResponseMixin):
template_name_field = None
template_name_suffix = '_detail'
def get_template_names(self):
# 省略....
if isinstance(self.object, models.Model):
object_meta = self.object._meta
names.append("%s/%s%s.html" % (
object_meta.app_label,
object_meta.model_name,
self.template_name_suffix
))
elif getattr(self, 'model', None) is not None and issubclass(self.model, models.Model):
names.append("%s/%s%s.html" % (
self.model._meta.app_label,
self.model._meta.model_name,
self.template_name_suffix
))
return names
DetailView
class DetailView(SingleObjectTemplateResponseMixin, BaseDetailView):
"""
Render a "detail" view of an object.
By default this is a model instance looked up from `self.queryset`, but the
view will support display of *any* object by overriding `self.get_object()`.
"""
总结
-
SingleObjectMixin.get_context_data
获取含有单个对象的上下文(context
) -
SingleObjectTemplateResponseMixin.render_to_response
利用上下文进行渲染并返回响应,并重写其get_template_names方法
-
BaseDetailView组合SingleObjectMixin和View
并实现get
请求和分发 -
DetailView
组合SingleObjectTemplateResponseMixin
和BaseDetailView
实现完整的逻辑处理