Py009-01-02CBV基本使用

CBV结构实现的原理

StudentsView 的 get/post等方法如何调用的呢?

  • 反射——(反射代码在哪里?)
1
2
3
4
5
6
7
8
9
10
11
12
13
from django.views import  View;
class StudentsView(View):
def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

urls.py里 as_view函数

1
2
3
4
5
6
# 在路由系统里永远是 一个url 对应一个函数
urlpatterns = [
re_path(r'^students/', views.StudentsView.as_view())
]
# views.StudentsView.as_view() 返回一个函数
# StudentsView 本身没有 as_view 方法 => 它的父类 View 里

View 源码里的 as_view

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
def as_view(cls, **initkwargs):
"""Main entry point for a request-response process."""
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
# 定义了一个view 函数并返回
def view(request, *args, **kwargs):
# cls就是当前请求的类 StudentsView
# self = StudentsView() 实例化
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 返回当前的 dispatch 方法 =》 一个请求进来实际是执行 dispatch
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs

# take name and docstring from class
update_wrapper(view, cls, updated=())

# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view

dispatch

1
2
3
4
5
6
7
8
9
10
11
class View:
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

def dispatch(self, request, *args, **kwargs):
# 获取请求方式 get/post/put/delete
if request.method.lower() in self.http_method_names:
# 反射
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)

经典面试题:你知道的http请求方式有哪些

1
2
3
4
5
6
7
8
9
10
[
'get', #查
'post', #增加
'put', #更新
'patch', #局部
'delete', #删除
'head',
'options',
'trace'
]

原理

1
url => view方法 => dispatch方法 => (反射执行其他 get/post/put/delete)
  • 请求进来要先执行 dispatch方法

定制自己的 dispatch 方法

  • 触发 dispatch 之前/之后 做一些操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.views import  View;
class StudentsView(View):
def dispatch(self, request, *args, **kwargs):
# 调用 父类的 dispatch
print('before')
ret = super(StudentsView,self).dispatch(request, *args, **kwargs)
print('after')
return ret

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');

多个类公用功能,为了避免重复编写

假如此时有个TeachersView,这样要复制两份dispatch

  • 使用继承
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
35
36
class MyBaseView(object):
def dispatch(self, request, *args, **kwargs):
# 调用 父类的 dispatch
print('before')
ret = super(StudentsView, self).dispatch(request, *args, **kwargs)
print('after')
return ret

class StudentsView(MyBaseView,View):

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');


class TeachersView(MyBaseView,View):

def get(self,request,*args,**kwargs):
return HttpResponse('get');

def post(self,request,*args,**kwargs):
return HttpResponse('post');

def put(self,request,*args,**kwargs):
return HttpResponse('put');

def delete(self,request,*args,**kwargs):
return HttpResponse('delete');