Django有3种视图:
函数视图 FBV
类视图 CBV
通用视图 CBGV
函数视图 FBV
通过条件分支来处理不同http请求
# 函数视图 FBV
def my_view(request):
if request.method == 'GET':
return HttpResponse("xxx")
elif request.method == 'POST':
return HttpResponse("xxx")
elif request.method == 'DELETE':
return HttpResponse("xxx")
1
2
3
4
5
6
7
8
# urls
from . import views
urlpatterns = [
path('', views.my_view, name='index')
]
1
2
3
4
5
缺点:函数式编程-面向过程,代码复用率低
类视图 CBV
继承自View类,通过不同实例方法来响应http请求
# 面向对象编程
from django.views.generic import View
class MyView(View):
def get(self,request,*args,**kwargs):
pass
def post(self,request,*args,**kwargs):
pass
1
2
3
4
5
6
7
8
# urls
from . import views
# 使用as_view()方法,为基于类的视图提供一个类似函数的入口
urlpatterns = [
path('', views.MyView.as_view(), name='index')
]
1
2
3
4
5
6
7
通用视图 CBGV
在类视图上更进一步,把增删改查操作的具体方法抽象出来,使用更少的代码实现功能
以通用显示视图 DetailView 为例:
该视图从以下视图继承方法和属性,MRO顺序:
想了解MRO的具体原理移步我的另一篇博文: https://blog.csdn.net/weixin_44955304/article/details/105175789
DetailView(自身)
django.views.generic.detail.SingleObjectTemplateResponseMixin
django.views.generic.base.TemplateResponseMixin
django.views.generic.detail.BaseDetailView
django.views.generic.detail.SingleObjectMixin
django.views.generic.base.ContextMixin
django.views.generic.base.View
方法流程图
具有(可重写-自定义)的类属性
属性 Defined in
content_type = None TemplateResponseMixin
context_object_name = None SingleObjectMixin
extra_context = None ContextMixin
http_method_names = [‘get’, ‘post’, ‘put’, ‘patch’, ‘delete’, ‘head’, ‘options’, ‘trace’] View
model = None SingleObjectMixin
pk_url_kwarg = ‘pk’ SingleObjectMixin
query_pk_and_slug = False SingleObjectMixin
queryset = None SingleObjectMixin
response_class =
slug_field = ‘slug’ SingleObjectMixin
slug_url_kwarg = ‘slug’ SingleObjectMixin
template_engine = None TemplateResponseMixin
template_name = None TemplateResponseMixin
template_name_field = None SingleObjectTemplateResponseMixin
template_name_suffix = ‘_detail’ SingleObjectTemplateResponseMixin
按照Django官方文档所述流程看,通用类视图代码
setup
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
self.request = request
self.args = args
self.kwargs = kwargs
1
2
3
4
5
dispatch()
def dispatch(self, request, *args, **kwargs):
# 当request 请求参数在自定义类属性self.http_method_names中
if request.method.lower() in self.http_method_names:
# 处理器 = 获取当前类的request.method.lower()值,默认获取值为self.http_method_not_allowed
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
# 或者请求参数不存在
else:
handler = self.http_method_not_allowed
# handler = get/post/delete... 与上文类视图 处理请求类似
return handler(request, *args, **kwargs)
1
2
3
4
5
6
7
8
9
10
http_method_not_allowed()
def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning('Method Not Allowed (%s): %s', request.method, request.path,
extra={
'status_code': 405,
'request': request
}
)
return http.HttpResponseNotAllowed(self._allowed_methods())
1
2
3
4
5
6
7
8
def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
1
2
get_template_names()
有两个类(SingleObjectTemplateResponseMixin/TemplateResponseMixin )定义了该函数,按照MRO算法,此处使用的是SingleObjectTemplateResponseMixin中定义的get_template_names()
ps: SingleObjectTemplateResponseMixin类继承自TemplateResponseMixin类
def get_template_names(self):
try:
# 调用父类TemplateResponseMixin中的get_template_names()方法
names = super().get_template_names()
except ImproperlyConfigured:
# If template_name isn't specified, it's not a problem --
# we just start with an empty list.
names = []
# 如果设置了self.template_name_字段,则获取该字段的值
if self.object and self.template_name_field:
name = getattr(self.object, self.template_name_field, None)
if name:
names.insert(0, name)
# 仅当所讨论的对象是模型时才使用此选项
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
))
# If we still haven't managed to find any template names, we should
# re-raise the ImproperlyConfigured to alert the user.
if not names:
raise
return names
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning(
'Method Not Allowed (%s): %s', request.method, request.path,
extra={'status_code': 405, 'request': request}
)
return HttpResponseNotAllowed(self._allowed_methods())
1
2
3
4
5
6
get_slug_field()
def get_slug_field(self):
"""Get the name of a slug field to be used to look up by slug."""
return self.slug_field
1
2
3
get_queryset()
def get_queryset(self):
"""
Return the `QuerySet` that will be used to look up the object.
This method is called by the default implementation of get_object() and
may not be called if get_object() is overridden.
"""
# 如果self.queryset属性 没有自定义
if self.queryset is None:
# 如果定义了 self.model 属性
if self.model:
# 返回模型类的所有查询集(_default_manager代表Model的默认管理器)
return self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
# 返回自定义查询集的 所有查询结果
return self.queryset.all()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
get_object()
def get_object(self, queryset=None):
"""
返回视图显示的对象。
在url参数中要求 `self.queryset` and a `pk` or `slug` .
S子类可以重写此项以返回任何对象。
"""
# Use a custom queryset if provided; this is required for subclasses
# like DateDetailView
if queryset is None:
queryset = self.get_queryset()
# Next, try looking up by primary key.
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)
# Next, try looking up by 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
get_context_object_name()
def get_context_object_name(self, obj):
"""Get the name to use for the object."""
if self.context_object_name:
return self.context_object_name
elif isinstance(obj, models.Model):
return obj._meta.model_name
else:
return None
1
2
3
4
5
6
7
8
get_context_data()
同样有两个类(SingleObjectMixin/ContextMixin)实现了改方法 ,按照MRO,该方法属于SingleObjectMixin
def get_context_data(self, **kwargs):
"""Insert the single object into the context dict."""
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)
1
2
3
4
5
6
7
8
9
10
get()
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)
1
2
3
4
render_to_response()
def render_to_response(self, context, **response_kwargs):
"""
Return a response, using the `response_class` for this view, with a
template rendered with the given context.
Pass response_kwargs to the constructor of the response class.
"""
response_kwargs.setdefault('content_type', self.content_type)
# response_class =
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
using=self.template_engine,
**response_kwargs
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TemplateResponse: 标准的HttpResponse对象是静态构造的,TemplateResponse对象则是惰性构造的,它保持自己的所有上下文、模板用以构造真正的response,但只有在最后需要的时候才真正进行渲染。Django之通用类视图DetailView_Miles_sudo的博客-CSDN博客