天天看點

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

要有删除确認頁面;