天天看点

102django_cbv

目录

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两者各有优劣;

102django_cbv
102django_cbv

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;

102django_cbv

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;

102django_cbv

        {% 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;

102django_cbv

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()),

102django_cbv

要有删除确认页面;