目錄
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兩者各有優劣;

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:
class AboutView(TemplateView): #ver3,CBV用法2
template_name = 'blog/about.html'
url(r'^about/', AboutView.as_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):
def post(self, request):
def head(self, request):
# url(r'^myview', views.my_view),
url(r'^myview', MyView.as_view()),
class GreetingView(View):
greeting = 'good day'
return HttpResponse(self.greeting)
class MorningGreetingView(GreetingView):
greeting = 'morning to yo'
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封裝成可擴充的類,使用時直接繼承,快速實作;
多對象;
預設提供的上下文是object_list,也可用context_object_name指定;
queryset、get_queryset、model;
可指定template_name;
def publisher_list(request):
publishers = Publisher.objects.all()
return render(request, 'books/publishers.html', {'publishers': publishers})
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()
<body>
<ul>
{% for publisher in object_list %}
<h3>{{ publisher }}</h3>
{% endfor %}
</ul>
</body>
# url(r'^$', views.publisher_list, name='publishers'),
url(r'^$', PublisherList.as_view(), name='publisher'),
單個對象的詳情;
get_context_data();
context_object_name;
{% for book in book_list %}
{{ book }}<br/>
{{ book.publisher }}
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'^(?P<pk>[0-9]+)/$', PublisherDetail.as_view()),
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'^add', PublisherView.as_view()),
根據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']
return super().form_valid(form)
context = {'extra': 'some context'}
kwargs.update(context)
return super().get_context_data(**kwargs)
url(r'^author/', AuthorCreate.as_view()),
要有删除确認頁面;