# urls.py
from django.conf.urls import url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^about/', TemplateView.as_view(template_name="about.html")),
]
Equal to
# views.py
class AboutView(TemplateView):
template_name = "about.html"
# urls.py
from django.conf.urls import url
from some_app.views import AboutView
urlpatterns = [
url(r'^about/', AboutView.as_view()),
]
from django.http import HttpResponse
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')
Equal to
# views.py
from django.http import HttpResponse
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')
# urls.py
from django.conf.urls import url
from myapp.views import MyView
urlpatterns = [
url(r'^about/', MyView.as_view()),
]
from django.http import HttpResponse
from django.views.generic import View
# 类的继承
class GreetingView(View):
greeting = "Good Day"
def get(self, request):
return HttpResponse(self.greeting)
class MorningGreetingView(GreetingView):
greeting = "Morning to ya"
# 类的覆盖
# urls.py
urlpatterns = [
url(r'^about/', GreetingView.as_view(greeting="G'day")),
]
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):
# 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):
# 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, update=())
# 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):
# 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)]
class ContextMixin(object):
# A default context mixin that passes the keyword arguments received by get_context_data as the template context.
def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs
class TemplateResponseMixin(object):
# A mixin that can be used to render a template.
template_name = None
template_engine = None
response_class = TemplateResponse
content_type = None
def render_to_response(self, context, **response_kwargs):
# Returns a response, using the 'response_class' for this view, with a template rendered with the given context.
# If any keyword arguments are provided, they will be passed to the constructor of the response class.
response_kwargs.setdefault('content_type', self.content_type)
return self.response_class(
request=self.request,
template=self.get_template_names(),
context=context,
using=self.template_engine,
**response_kwargs
)
def get_template_names(self):
# Returns a list of template names to be used for the request. Must return a list.
# May not be called if render_to_response is overridden.
if self.template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'")
else:
return [self.template_name]
class TemplateView(TemplateResponseMixin, ContextMixin, View):
# A view that renders a template. This view will also pass into the context any keyword arguments passed by the URLconf.
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **initkwargs):
view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
return login_required(view)
class MyView(LoginRequiredMixin, ...):
# this is a generic view
...
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
# models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
ordering = ['-name']
def __str__(self): # __unicode__ on Python 2
return self.name
class Author(models.Model):
salutation = models.CharField(max_length=10)
name = models.CharField(max_length=200)
email = models.EmailField()
headshot = models.ImageField(upload_to='author_headshots')
def __str__(self): # __unicode__ on Python 2
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField('Author')
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
publication_date = models.DateField()
# books/views.py
# General function version
def Publisher_list(request):
publishers = Publisher.objects.all()
return render(request, 'publisher_list.html', {'publishers': publishers})
# books/views.py
# Django class base view generic class view
from django.views.generic import ListView
from books.models import Publisher
class PublisherList(ListView):
model = Publisher
# queryset = Publisher.objects.all()
# queryset = Publisher.objects.filter(ip='127.0.0.1')
# context = {'object_list': queryset}
# context_object_name = 'publishers'
# template_name = /_list.html
# template_name = 'books/publisher_list.html'
# def get_queryset(self):
# return Publisher.objects.all()
# books/templates/books/publisher_list.html
{% extends "base.html" %}
{% block content %}
Publishers
{% for publisher in object_list %}
- {{ publisher.name }}
{% endfor %}
{% endblock %}
显示一个object的详情页面。
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetail(DetailView):
model = Publisher
content_object_name = 'publisher'
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
# def get_object(self):
# object = super(PublisherDetail, self).get_object()
# object.last_accessed = timezone.now()
# object.save()
# return object
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
# views.py
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super(ContactView, self).form_valid(form)
# models.py
from django.urls import reverse_lazy
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse_lazy0('author-detail', kwargs={'pk': self.pk})
# views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
fields = ['name']
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
# urls.py
from django.conf.urls import url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = [
url(r'author/add/$', AuthorCreate.as_view(), name='author-add'),
url(r'author/(?P[0-9]+)/$', AuthorUpdate.as_view(), name='author-update'),
url(r'author/(?P[0-9]+)/delete/$', AuthorDelete.as_view(), name='author-delete'),
]
如果我们需要在Publisher的详情页面里展现该出版社的图书,显然有SingleObject,也有MultiObject。
# views.py
from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher
class PublisherDetail(SingleObjectMixin, ListView):
paginate_by = 2
template_name = "books/publisher_detail.html"
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Publisher.objects.all())
return super(PublisherDetail, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(PublisherDetail, self).get_context_data(**kwargs)
context['publisher'] = self.object
return context
def get_queryset(self):
return self.object.book_set.all()
# publisher_detail.html
{% extends "base.html" %}
{% block content %}
Publisher {{ publisher.name }}
{% for book in page_obj %}
- {{ book.title }}
{% endfor %}
{% endblock %}
DetailView
ListView
UpdateView CreateView
使用Class Based View编写view更简洁,代码更少,但同时由于复杂的继承关系为理解带来不便,所以两者各有优势,需要自己决定使用哪种方式。想学好CBV,需要多研究几遍源码。