目录
django.views.generic.TemplateView.. 1
django.views.generic.View.. 2
类的继承和覆盖:... 5
自定义LoginRequiredMixin:... 5
通用视图:... 6
django.views.generic.ListView.. 6
django.views.generic.DetailView.. 8
django.views.generic.FormView:... 9
django.views.generic.CreateView:... 9
django.views.generic.UpdateView:... 9
cbv,class based view:
基于类的视图,使编写view更简洁,有复杂的继承关系;
CBV和FBV两者各有优劣;
django.views.generic.TemplateView
UML图;
Mixin增强功能,提供一些方法,如TemplateResponseMixin提供了render_to_response()渲染模板,ContextMixin提供get_context_data();
View提供get,post访问入口;
例,ver1:
def about(request): #ver1,FBV用法
return render(request, 'blog/about.html')
url(r'^about/', views.about, name='about'),
例,ver2:
from django.views.generic import TemplateView
app_name = 'blog'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^login/', views.auth_login, name='login'),
url(r'^logout/', views.auth_logout, name='logout'),
# url(r'^about/', views.about, name='about'),
url(r'^about/', TemplateView.as_view(template_name='blog/about.html')), #ver2,CBV用法1
]
例,ver3:
from django.views.generic import TemplateView
class AboutView(TemplateView): #ver3,CBV用法2
template_name = 'blog/about.html'
url(r'^about/', AboutView.as_view()),
django.views.generic.View
View源码:
该类在没更改原来django逻辑的情况下,可用于编写view,每个http请求会使用对应类的同名的方法进行处理;
class View(object):
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs): #检查as_view()传入的参数是否在类中定义
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
for key, value in six.iteritems(kwargs):
setattr(self, key, value)
@classonlymethod
def as_view(cls, **initkwargs): #返回的是一个函数对象(装饰器);template_name=’blog/about.html’模板名作为参数传,或在类属性中定义,传入的参数可覆盖类中定义的属性
"""
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))
def view(request, *args, **kwargs):
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
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
def dispatch(self, request, *args, **kwargs): #根据用户的request method路由到get、post方法
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
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)
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)]
例,ver1,FBV:
def my_view(request):
if request.method == 'GET':
return HttpResponse('get it')
elif request.method == 'POST':
return HttpResponse('post it')
elif request.method == 'HEAD':
return HttpResponse('head it')
例,ver2,CBV,省去了if判断:
from django.views.generic import View
class MyView(View):
def get(self, request):
return HttpResponse('get it')
def post(self, request):
return HttpResponse('post it')
def head(self, request):
return HttpResponse('head it')
# url(r'^myview', views.my_view),
url(r'^myview', MyView.as_view()),
类的继承和覆盖:
class GreetingView(View):
greeting = 'good day'
def get(self, request):
return HttpResponse(self.greeting)
class MorningGreetingView(GreetingView):
greeting = 'morning to yo'
自定义LoginRequiredMixin:
class LoginRequiredMixin:
@classmethod
def as_view(cls, **initkwargs):
view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
return login_required(view)
class MyView(LoginRequiredMixin, View):
pass
装饰类:
from django.utils.decorators import method_decorator
class ProtectedView(TemplateView):
template_name = 'blog/about.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
通用视图:
generic class based view和class based view概念上不是一回事;
class based view是用类的方式写view;
generic class based view是用class based view方式将常用的CRUD封装成可扩展的类,使用时直接继承,快速实现;
django.views.generic.ListView
多对象;
默认提供的上下文是object_list,也可用context_object_name指定;
queryset、get_queryset、model;
可指定template_name;
例,ver1:
def publisher_list(request):
publishers = Publisher.objects.all()
return render(request, 'books/publishers.html', {'publishers': publishers})
例,ver2:
from django.views.generic import ListView
class PublisherList(ListView): #默认去找suffix为list的模板,即publisher_list.html;publisher_list.html模板;默认的context为object_list
model = Publisher #返回Publisher.object.all(),多对象
# template_name = 'books/publishers.html' #
# context_object_name = #提供上下文
# queryset = Publisher.objects.all() #model|queryset|get_queryset()三者关系
# def get_queryset(self):
# return Publisher.objects.all()
{% for publisher in object_list %}
{{ publisher }}
{% endfor %}
# url(r'^$', views.publisher_list, name='publishers'),
url(r'^$', PublisherList.as_view(), name='publisher'),
django.views.generic.DetailView
单个对象的详情;
get_context_data();
context_object_name;
{{ publisher }}
{% for book in book_list %}
{{ book }}
{{ book.publisher }}
{% endfor %}
from django.views.generic import DetailView
from .models import Book
class PublisherDetail(DetailView):
model = Publisher
context_object_name = 'publisher'
def get_context_data(self, **kwargs):
context = super(PublisherDetail, self).get_context_data(**kwargs)
context['book_list'] = Book.objects.all()
return context
url(r'^$', PublisherList.as_view(), name='publisher'),
url(r'^(?P
django.views.generic.FormView:
class PublisherForm(forms.Form):
name = forms.CharField(label=_('Your name'), max_length=30)
address = forms.CharField(max_length=50)
city = forms.CharField(max_length=60)
state_province = forms.CharField(max_length=30)
country = forms.CharField(max_length=20)
website = forms.CharField(max_length=50)
def send_mail(self):
print('~~~~~~~~~~~send_mail() OK')
from django.views.generic import FormView
class PublisherView(FormView):
form_class = PublisherForm
template_name = 'books/books_add.html'
success_url = '/books/'
def form_valid(self, form):
form.send_mail()
return super(PublisherView, self).form_valid(form)
url(r'^$', PublisherList.as_view(), name='publisher'),
url(r'^add', PublisherView.as_view()),
django.views.generic.CreateView:
根据model和fields动态构建form,另form_class = forms.AuthorForm等价于model和fields;
model + fields = form_class,另get_form_class、get_form;
template_name,不指定默认找suffix为_form.html;
success_url,get_success_url;
form_valid()、form_invalid(),注意重写都要调用父类方法;
get_context_data;
success_message、get_success_message;
from django.views.generic import CreateView
from .models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['first_name', 'last_name', 'email']
success_url = '/books/'
def form_valid(self, form):
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = {'extra': 'some context'}
kwargs.update(context)
return super().get_context_data(**kwargs)
url(r'^author/', AuthorCreate.as_view()),
django.views.generic.UpdateView:
django.views.generic.DeleteView:
要有删除确认页面;