本节内容
| 一 Class Based View 基于类的视图 |
function view 存在问题,无法继承复用,尤其时框架封装好的类用不了,function组装复用更擅长
class based view 代码更简洁
简单样例
version 1
# urls.py from django.conf.urls import url from mysite import views as my_view urlpatterns = [ url(r'^about/', my_view.about), ] # mysite/views.py from django.shortcuts import render def about(request): return render(request, 'about.html')
基本的function based view
version 2
# urls.py from django.views.generic import TemplateView urlpatterns = [ url(r'^about/', TemplateView.as_view(template_name='about.html')), ] # mysite/views.py from django.shortcuts import render def about(request): return render(request, 'about.html')
TemplateView.as_view(template_name='about.html')) 方法 as_view(),参数template_name=‘网页模板’
version 3
# mysite/views.py from django.views.generic import TemplateView class AboutView(TemplateView): template_name = 'about.html' #mysite/urls.py from mysite import views as my_view urlpatterns = [ url(r'^about/', my_view.AboutView.as_view()), ]
说明:
-
as_view()返回的是一个function object
-
模板名字作为as_view参数传进去,也可以作为类变量设置template_name = '网页模板'
1. 类的视图 View
# mysite/views.py
def my_view(request): if request.method == 'GET': return render(request, 'about.html') elif request.method == 'POST': return HttpResponse('post it') elif request.method == 'HEAD': return HttpResponse('head it')
# mysite/urls.py from mysite import views urlpatterns = [ url(r'^about/', views.my_view), ]
等价于 类图公共基类View
# mysite/views.py from django.shortcuts import render,HttpResponse from django.views.generic import View class MyView(View): def get(self, request): return render(request, 'about.html') def post(self, request): return HttpResponse('post it') def head(self, request): return HttpResponse('head it') # mysite/urls.py from mysite import views as my_view urlpatterns = [ url(r'^about/', my_view.MyView.as_view()), ]
类视图好处就是可以直接继承和覆盖
# mysite/views.py from django.views.generic import View class GreetingView(View): greeting = 'Good Day' def get(self, request): return HttpResponse(self.greeting) class MorningGreeting(GreetingView): greeting = 'Morning to ya' # mysite/urls.py urlpatterns = [ my_view.GreetingView.as_view(greeting="G'day")), ]
源码分析
class View(object): # 所有views的公共类,仅仅实现 dispatch方法和简单安全性验证 http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): for key, value in six.iteritems(kwargs): setattr(self, key, value) @classonlymethod def as_view(cls, **initkwargs): # request-response的主入口点 for key in initkwargs: # 不能有get,post等方法名的参数,后续有setattr()操作,会覆盖原始请求方法 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__)) # 如果传入了一个没有定义的类属性,就报错;如有greeting属性,就不报错 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)) # 定义了类似闭包的视图函数 def view(request, *args, **kwargs): self = cls(**initkwargs) # 调用__init__()进行实例化 if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) # 调用 self.dispatch()进行处理 # 对view object设置了一些属性 view.view_class = cls view.view_initkwargs = initkwargs # 更新文档说明 update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view def dispatch(self, request, *args, **kwargs): # 将request.method反射到类相应的方法上,并执行 if request.method.lower() in self.http_method_names: # 如果有如get,就handler=get;如果没有handler = self.http_method_not_allowed handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) 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()) def options(self, request, *args, **kwargs): """ Handles responding to requests for the OPTIONS HTTP verb. """ response = http.HttpResponse() response['Allow'] = ', '.join(self._allowed_methods()) response['Content-Length'] = '0' return response def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)]