django class-based views: survival guide for novices (v2)

Post on 18-Dec-2014

359 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

The slides of the presentation I gave at DjangoVillage 2014 in Orvieto. Are you a Django novice, confused by words like class-based views, URL dispatchers, HTTP requests? Are you still wondering how to use all those things to build the pages of your Web site? Django programmers that started with versions prior to 1.3 are used to deal with views as functions, and they learned how to process even complex forms in a procedural way. From the release 1.3, Django introduced class-based views (CBVs) and ported its powerful generic views to this new paradigm (class-based generic views, or CBGVs). This change, however, has not been harmless for Django novices: the django-users mailing list and StackOverflow are full of questions about views and classes. This talk aims to lead Django novices to a good understanding of what class-based functions are and how they can be effectively used. The main topics are: * Python classes: how OOP concepts improve the View part of Django MVT. This part aims to introduce Python classes as data processors and explains how OOP concepts like inheritance help the fast development of customized solutions. * URL dispatchers: how Django CBV process URL parameters. Here I discuss how Django class-based views store arguments extracted from URLs and how we can access them. * HTTP verbs: how Django CBV deal with GET, POST and friends. This part shows what happens to a class-based view when HTTP requests are processed and how to leverage the mechanism to customize data processing. * CRUD operations through Django generic class-based views. Create, Read, Update, Delete are the fundamentals operations you need on data, so it is worth learning to use and customize the powerful generic views of Django that implement them. The target of this talk are Django novices who completed and understood the Django tutorial. Previous knowledge of the basic Python OOP syntax and concepts is preferred (classes, inheritance, method overriding, function arguments processing). http://lgiordani.com https://twitter.com/tw_lgiordani/

TRANSCRIPT

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#1/82

Django class-based viewsSurvival guide for novices

Leonardo Giordani

@tw_lgiordani – lgiordani.github.com

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#2/82About me

Leonardo Giordanihttp://lgiordani.github.io

https://twitter.com/tw_lgiordani

https://github.com/lgiordani

https://plus.google.com/u/LeonardoGiordani

Feel free to contact meQuestions, suggestions, corrections are always warmly welcome

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#3/82

Django novices who completed and understood the Django tutorial.

Knowledge of the basic Python OOP syntax and concepts is useful

(classes, inheritance, method overriding, function arguments processing).

About you

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#4/82

What do you mean with “class-based”? What happened to

functional views?

How do I manage

forms with CBVs?

How can I change the

content of a view?

What is the advantage of

Class-Based views?

Get request object in class-based View

Where does self.kwargs

come from?

I hate Django class-based views

This is black magic, isn't it?

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#5/82

What are Django views?

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#6/82

Django is a processor of HTTP requests

DjangoHTTP REQUEST HTTP RESPONSE

Django views

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#7/82

A view is the part of Django that processes a specific request

(a given set of URLs)

Django views

Django

view1

view2

HTTP REQUEST HTTP RESPONSE

UR

L d

isp

atch

er

Tem

pla

te e

ng

ineURL1

URL2

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#8/82

view

enhanced view

A view (as any processing system) can be monolithic.

This makes hard to replace or enhance part of it.

Django views

HTTP REQUEST

HTTP REQUEST

HTTP RESPONSE

HTTP RESPONSE

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#9/82

A system can be splitted in several components.

This makes easier to change part of it.

view:step1 view:step2 view:step3

view:step1 view:step2 view:step3

Django views

HTTP REQUEST

HTTP REQUEST

HTTP REQUEST

HTTP REQUEST

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#10/82Object-oriented programming

Modularization

Small components that may be easily changed

Delegation

Inheritance and composition allow heavy code reuse

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#11/82Class-based views

from django.views.generic.list import ListViewfrom articles.models import Articlefrom django.conf.urls import url

class ArticleListView(ListView):    model = Article

urlpatterns = [    url(r'^articles/$', ArticleListView.as_view()),]

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#12/82

from django.views.generic.list import ListViewfrom articles.models import Articlefrom django.conf.urls import url

class ArticleListView(ListView):    model = Article

urlpatterns = [    url(r'^articles/$', ArticleListView.as_view()),]

This routes HTTP requests to the 'articles/' URL to the ArticleListView view.

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#13/82

from django.views.generic.list import ListViewfrom articles.models import Articlefrom django.conf.urls import url

class ArticleListView(ListView):    model = Article

urlpatterns = [    url(r'^articles/$', ArticleListView.as_view()),]

This defines the view as a copy of ListView working on the

Article model.

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#14/82

● Processes incoming HTTP GET requests

● Loads all Article objects

● Renders a template called article_list.html and the list of articles is in the

object_list variable

class ArticleListView(ListView):    model = Article

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#15/82

What happens behind the scenes?

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#16/82

Use the source, Luke!*

https://github.com/django/django

* Jeff Atwood, 2012

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#17/82

Source is a moving target

https://github.com/django/django/tree/1.5.7

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#18/82

@classonlymethoddef as_view(cls, **initkwargs):    [...]    def view(request, *args, **kwargs):        [...]            self.request = request        self.args = args        self.kwargs = kwargs        return self.dispatch(request, *args, **kwargs)    [...]    return view

django/views/generic/base.py#L46

url(r'^articles/$', ArticleListView.as_view())GETrequest

as_view

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#19/82

@classonlymethoddef as_view(cls, **initkwargs):    [...]    def view(request, *args, **kwargs):        [...]            self.request = request        self.args = args        self.kwargs = kwargs        return self.dispatch(request, *args, **kwargs)    [...]    return view

django/views/generic/base.py#L46

url(r'^articles/$', ArticleListView.as_view())GETrequest

as_view

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#20/82

GETrequest

as_view

dispatch

def dispatch(self, request, *args, **kwargs):    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)

django/views/generic/base.py#L78

return self.dispatch(request, *args, **kwargs)

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#21/82

GETrequest

as_view

dispatch

def dispatch(self, request, *args, **kwargs):    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)

django/views/generic/base.py#L78

return self.dispatch(request, *args, **kwargs)

'GET'  ­­> getattr(self, 'get', [...])'POST' ­­> getattr(self, 'post', [...])'PUT'  ­­> getattr(self, 'put', [...])[...]

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#22/82

GETrequest

as_view

dispatch

get

return self.get(request, *args, **kwargs)

def get(self, request, *args, **kwargs):    self.object_list = self.get_queryset()    allow_empty = self.get_allow_empty()    if not allow_empty:        if (self.get_paginate_by(self.object_list) is not None            and hasattr(self.object_list, 'exists')):            is_empty = not self.object_list.exists()        else:            is_empty = len(self.object_list) == 0        if is_empty:            raise Http404 [...]    context = self.get_context_data(object_list=self.object_list)    return self.render_to_response(context)

django/views/generic/list.py#L123

class BaseListView(MultipleObjectMixin, View):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#23/82

GETrequest

as_view

dispatch

get

return self.get(request, *args, **kwargs)

def get(self, request, *args, **kwargs):    self.object_list = self.get_queryset()    allow_empty = self.get_allow_empty()    if not allow_empty:        if (self.get_paginate_by(self.object_list) is not None            and hasattr(self.object_list, 'exists')):            is_empty = not self.object_list.exists()        else:            is_empty = len(self.object_list) == 0        if is_empty:            raise Http404 […]    context = self.get_context_data(object_list=self.object_list)    return self.render_to_response(context)

django/views/generic/list.py#L123

class BaseListView(MultipleObjectMixin, View):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#24/82

GETrequest

as_view

dispatch

get

self.object_list = self.get_queryset()

def get_queryset(self):    if self.queryset is not None:        queryset = self.queryset        if hasattr(queryset, '_clone'):            queryset = queryset._clone()    elif self.model is not None:        queryset = self.model._default_manager.all()    else:        raise ImproperlyConfigured [...]    return queryset

get_queryset

django/views/generic/list.py#L22

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#25/82

GETrequest

as_view

dispatch

get

self.object_list = self.get_queryset()

def get_queryset(self):    if self.queryset is not None:        queryset = self.queryset        if hasattr(queryset, '_clone'):            queryset = queryset._clone()    elif self.model is not None:        queryset = self.model._default_manager.all()    else:        raise ImproperlyConfigured [...]    return queryset

get_queryset

class ArticleListView(ListView):    model = Article

django/views/generic/list.py#L22

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#26/82

GETrequest

as_view

dispatch

get

return self.get(request, *args, **kwargs)

def get(self, request, *args, **kwargs):    self.object_list = self.get_queryset()    allow_empty = self.get_allow_empty()    if not allow_empty:        if (self.get_paginate_by(self.object_list) is not None            and hasattr(self.object_list, 'exists')):            is_empty = not self.object_list.exists()        else:            is_empty = len(self.object_list) == 0        if is_empty:            raise Http404 […]    context = self.get_context_data(object_list=self.object_list)    return self.render_to_response(context)

django/views/generic/list.py#L123

class BaseListView(MultipleObjectMixin, View):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#27/82

GETrequest

as_view

dispatch

get

context = self.get_context_data(object_list=self.object_list)

def get_context_data(self, **kwargs):    queryset = kwargs.pop('object_list')    page_size = self.get_paginate_by(queryset)    context_object_name = self.get_context_object_name(queryset)    if page_size:        [...]    else:        context = {            'paginator': None,            'page_obj': None,            'is_paginated': False,            'object_list': queryset        }    if context_object_name is not None:       context[context_object_name] = queryset    context.update(kwargs)    return super(MultipleObjectMixin, self).get_context_data(**context)

get_context_data

django/views/generic/list.py#L91

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#28/82

GETrequest

as_view

dispatch

get

context = self.get_context_data(object_list=self.object_list)

def get_context_data(self, **kwargs):    queryset = kwargs.pop('object_list')    page_size = self.get_paginate_by(queryset)    context_object_name = self.get_context_object_name(queryset)    if page_size:        [...]    else:        context = {            'paginator': None,            'page_obj': None,            'is_paginated': False,            'object_list': queryset        }    if context_object_name is not None:       context[context_object_name] = queryset    context.update(kwargs)    return super(MultipleObjectMixin, self).get_context_data(**context)

get_context_data

django/views/generic/list.py#L91

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#29/82

GETrequest

as_view

dispatch

get

context_object_name = self.get_context_object_name(queryset)

def get_context_object_name(self, object_list):    if self.context_object_name:        return self.context_object_name    elif hasattr(object_list, 'model'):        return '%s_list' % object_list.model._meta.object_name.lower()    else:        return None

get_context_data

django/views/generic/list.py#L80

get_context_object_name

class ArticleListView(ListView):    model = Article

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#30/82

GETrequest

as_view

dispatch

get

return self.get(request, *args, **kwargs)

def get(self, request, *args, **kwargs):    self.object_list = self.get_queryset()    allow_empty = self.get_allow_empty()    if not allow_empty:        if (self.get_paginate_by(self.object_list) is not None            and hasattr(self.object_list, 'exists')):            is_empty = not self.object_list.exists()        else:            is_empty = len(self.object_list) == 0        if is_empty:            raise Http404 […]    context = self.get_context_data(object_list=self.object_list)    return self.render_to_response(context)

django/views/generic/list.py#L123

class BaseListView(MultipleObjectMixin, View):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#31/82

GETrequest

as_view

dispatch

get

return self.render_to_response(context)

def render_to_response(self, context, **response_kwargs):    response_kwargs.setdefault('content_type', self.content_type)    return self.response_class(        request = self.request,        template = self.get_template_names(),        context = context,        **response_kwargs    )

django/views/generic/base.py#L118

render_to_response

class TemplateResponseMixin(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#32/82

GETrequest

as_view

dispatch

get

return self.render_to_response(context)

def render_to_response(self, context, **response_kwargs):    response_kwargs.setdefault('content_type', self.content_type)    return self.response_class(        request = self.request,        template = self.get_template_names(),        context = context,        **response_kwargs    )

django/views/generic/base.py#L118

render_to_response

class TemplateResponseMixin(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#33/82

GETrequest

as_view

dispatch

get

template = self.get_template_names()

def get_template_names(self):    try:        names = super(MultipleObjectTemplateResponseMixin,                      self).get_template_names()    except ImproperlyConfigured:        names = []    

if hasattr(self.object_list, 'model'):        opts = self.object_list.model._meta        names.append("%s/%s%s.html"          % (opts.app_label,             opts.object_name.lower(),             self.template_name_suffix))

    return names

django/views/generic/list.py#L149

render_to_response

get_template_names

class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#34/82

GETrequest

as_view

dispatch

get

names = super([...]).get_template_names()

def get_template_names(self):    if self.template_name is None:        raise ImproperlyConfigured([...])    else:        return [self.template_name]

django/views/generic/base.py#L134

render_to_response

get_template_names

get_template_names

class TemplateResponseMixin(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#35/82

GETrequest

as_view

dispatch

get

template = self.get_template_names()

def get_template_names(self):    try:        names = super(MultipleObjectTemplateResponseMixin,                      self).get_template_names()    except ImproperlyConfigured:        names = []    

if hasattr(self.object_list, 'model'):        opts = self.object_list.model._meta        names.append("%s/%s%s.html"          % (opts.app_label,             opts.object_name.lower(),             self.template_name_suffix))

    return names

django/views/generic/list.py#L149

render_to_response

get_template_names

class MultipleObjectTemplateResponseMixin(TemplateResponseMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#36/82

● Processes incoming HTTP GET requests

● Loads all Article objects

● Renders a template called article_list.html and the list of articles is in

the object_list variable

class ArticleListView(ListView):    model = Article

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#37/82

How do you customize CBVs behaviour?

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#38/82

GETrequest

as_view

class ArticleListView(ListView):    model = Article

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#39/82

GETrequest

as_view

dispatch

get

get_context_data

class ArticleListView(ListView):    model = Article

    def get_context_data(self, **kwargs):        context = super(ArticleListView,                        self).get_context_data(**kwargs)        context['readers'] = Reader.objects.count()        return context

def get_context_data(self, **kwargs):    [...]

views/generic/list.py#L91

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#40/82

GETrequest

as_view

dispatch

get

get_queryset

class ArticleListView(ListView):    model = Article

    def get_queryset(self):        queryset = super(ArticleListView, self).get_queryset()        return queryset.filter([...])

def get_queryset(self):    [...]

views/generic/list.py#L91

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#41/82

Arguments in class-based views

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#42/82

@classonlymethoddef as_view(cls, **initkwargs):    [...]    def view(request, *args, **kwargs):        [...]            self.request = request        self.args = args        self.kwargs = kwargs        return self.dispatch(request, *args, **kwargs)    [...]    return view

django/views/generic/base.py#L46

url(r'^articles/$', ArticleListView.as_view())GETrequest

as_view

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#43/82

@classonlymethoddef as_view(cls, **initkwargs):    [...]    def view(request, *args, **kwargs):        [...]            self.request = request        self.args = args        self.kwargs = kwargs        return self.dispatch(request, *args, **kwargs)    [...]    return view

django/views/generic/base.py#L46

url(r'^articles/$', ArticleListView.as_view())GETrequest

as_view

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#44/82

GETrequest

as_view

dispatch

get

get_queryset

class ArticleListView(ListView):    model = Article

    def get_queryset(self):        queryset = super(ArticleListView, self).get_queryset()        return queryset.filter(year=self.kwargs['year'])

https://docs.djangoproject.com/en/1.5/topics/http/urls/

url(r'^articles/(?P<year>\d{4})/$', ArticleListView.as_view()),

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#45/82

GETrequest

as_view

dispatch

get

get_context_data

class ArticleListView(ListView):    model = Article

    def get_context_data(self, **kwargs):      context = super(ArticleListView, self).                            get_context_data(**kwargs)      context['year'] = self.kwargs['year']      return context

https://docs.djangoproject.com/en/1.5/topics/http/urls/

url(r'^articles/(?P<year>\d{4})/$', ArticleListView.as_view()),

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#46/82

GETrequest

as_view

dispatch

get

context = self.get_context_data(object_list=self.object_list)

def get_context_data(self, **kwargs):    queryset = kwargs.pop('object_list')    page_size = self.get_paginate_by(queryset)    context_object_name = self.get_context_object_name(queryset)    if page_size:        [...]    else:        context = {            'paginator': None,            'page_obj': None,            'is_paginated': False,            'object_list': queryset        }    if context_object_name is not None:       context[context_object_name] = queryset    context.update(kwargs)    return super(MultipleObjectMixin, self).get_context_data(**context)

get_context_data

django/views/generic/list.py#L91

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#47/82

GETrequest

as_view

dispatch

get

context = self.get_context_data(object_list=self.object_list)

def get_context_data(self, **kwargs):    queryset = kwargs.pop('object_list')    page_size = self.get_paginate_by(queryset)    context_object_name = self.get_context_object_name(queryset)    if page_size:        [...]    else:        context = {            'paginator': None,            'page_obj': None,            'is_paginated': False,            'object_list': queryset        }    if context_object_name is not None:       context[context_object_name] = queryset    context.update(kwargs)    return super(MultipleObjectMixin, self).get_context_data(**context)

get_context_data

django/views/generic/list.py#L91

class MultipleObjectMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#48/82

GETrequest

as_view

dispatch

get

return super(MultipleObjectMixin, self).get_context_data(**context)

def get_context_data(self, **kwargs):        if 'view' not in kwargs:            kwargs['view'] = self        return kwargs

get_context_data

django/views/generic/base.py#15

get_context_data

class ContextMixin(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#49/82

class ArticleListView(ListView):    model = Article

    def get_context_data(self, **kwargs):      context = super(ArticleListView, self).                            get_context_data(**kwargs)      context['year'] = self.kwargs['year']      return context

urlpatterns = [    url(r'^articles/(?P<year>\d{4})/$', ArticleListView.as_view())]

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#50/82

class ArticleListView(ListView):    model = Article

urlpatterns = [    url(r'^articles/(?P<year>\d{4})/$', ArticleListView.as_view())]

[...]{{ view.kwargs.year }}[...]

http://reinout.vanrees.org/weblog/2014/05/19/context.html

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#51/82

ListView

MultipleObjectTemplateResponseMixin BaseListView

TemplateResponseMixin MultipleObjectMixin View

ContextMixin

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#52/82

ListView

MultipleObjectTemplateResponseMixin BaseListView

TemplateResponseMixin MultipleObjectMixin View

ContextMixinas_view()dispatch()as_view()dispatch()

get_context_data()

render_to_response()get_template_names()

get_queryset()get_context_data()get_context_object_name()

get()

get_template_names()

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#53/82

CRUD operations and forms

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#54/82

A Read operation is performed through a GET request,

while Create, Update and Delete are implemented with

other HTTP methods: POST, PUT, DELETE

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#55/82

GETrequest

as_view

dispatch

def dispatch(self, request, *args, **kwargs):    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)

django/views/generic/base.py#L78

return self.dispatch(request, *args, **kwargs)

'GET'  ­­> getattr(self, 'get', [...])'POST' ­­> getattr(self, 'post', [...])'PUT'  ­­> getattr(self, 'put', [...])[...]

class View(object):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#56/82

class RedirectView(View):    def get(self, request, *args, **kwargs):        [...]        return http.HttpResponseRedirect(url)

    def head(self, request, *args, **kwargs):        return self.get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):        return self.get(request, *args, **kwargs)

    def options(self, request, *args, **kwargs):        return self.get(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):        return self.get(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):        return self.get(request, *args, **kwargs)

django/views/generic/base.py#L157

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#57/82

What is the relationship between

forms and HTTP methods?

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#58/82

browser server

GET request

POST request

HTTP response

HTTP response

When you work with forms there are multiple interactions

with the view

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#59/82

from django.shortcuts import renderfrom django.http import HttpResponseRedirect

def contact(request):    if request.method == 'POST': # If the form has been submitted...        form = ContactForm(request.POST) # A form bound to the POST data        if form.is_valid(): # All validation rules pass            # Process the data in form.cleaned_data            # ...            return HttpResponseRedirect('/thanks/') # Redirect after POST    else:        form = ContactForm() # An unbound form

    return render(request, 'contact.html', {'form': form,})

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#60/82

● Processes incoming HTTP GET and POST requests

● Renders a template called stickynote_form.html and the editing form is

in the form variable

● Manages the creation (update, deletion) of a StickyNote entry

class NoteAdd(CreateView):    model = StickyNote

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#61/82

POSTrequest

as_view

dispatch

post

return self.post(request, *args, **kwargs)

def post(self, request, *args, **kwargs):    self.object = None    return super(BaseCreateView, self).post(request, *args,                                            **kwargs)

django/views/generic/edit.py#L197

class BaseCreateView(ModelFormMixin, ProcessFormView):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#62/82

POSTrequest

as_view

dispatch

post

return super().post(request, *args, **kwargs)

def post(self, request, *args, **kwargs):    form_class = self.get_form_class()    form = self.get_form(form_class)    if form.is_valid():        return self.form_valid(form)    else:        return self.form_invalid(form)

django/views/generic/edit.py#L157

post

class ProcessFormView(View):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#63/82

POSTrequest

as_view

dispatch

post

return super().post(request, *args, **kwargs)

def post(self, request, *args, **kwargs):    form_class = self.get_form_class()    form = self.get_form(form_class)    if form.is_valid():        return self.form_valid(form)    else:        return self.form_invalid(form)

django/views/generic/edit.py#L157

class ProcessFormView(View):

post

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#64/82

POSTrequest

as_view

dispatch

post

form_class = self.get_form_class()

django/views/generic/edit.py#L80

class ModelFormMixin(FormMixin, SingleObjectMixin):

post

get_form_class

def get_form_class(self):    if self.form_class:        return self.form_class    else:        if self.model is not None:            model = self.model        elif hasattr(self, 'object') and self.object is not None:            model = self.object.__class__        else:            model = self.get_queryset().model        return model_forms.modelform_factory(model)

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#65/82

POSTrequest

as_view

dispatch

post

django/views/generic/edit.py#L80

class ModelFormMixin(FormMixin, SingleObjectMixin):

post

get_form_class

def get_form_class(self):    if self.form_class:        return self.form_class    else:        if self.model is not None:            model = self.model        elif hasattr(self, 'object') and self.object is not None:            model = self.object.__class__        else:            model = self.get_queryset().model        return model_forms.modelform_factory(model)

form_class = self.get_form_class()

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#66/82

POSTrequest

as_view

dispatch

post

def post(self, request, *args, **kwargs):    form_class = self.get_form_class()    form = self.get_form(form_class)    if form.is_valid():        return self.form_valid(form)    else:        return self.form_invalid(form)

django/views/generic/edit.py#L157

class ProcessFormView(View):

post

return super().post(request, *args, **kwargs)

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#67/82

POSTrequest

as_view

dispatch

post

form = self.get_form(form_class)

def get_form(self, form_class):    return form_class(**self.get_form_kwargs())

django/views/generic/edit.py#L31

class FormMixin(ContextMixin):

post

get_form

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#68/82

POSTrequest

as_view

dispatch

post

return form_class(**self.get_form_kwargs())

def get_form_kwargs(self):    kwargs = super(ModelFormMixin, self).get_form_kwargs()    kwargs.update({'instance': self.object})    return kwargs

django/views/generic/edit.py#L100

class FormMixin(ContextMixin):

post

get_form_kwargs

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#69/82

POSTrequest

as_view

dispatch

post

kwargs = super().get_form_kwargs()

def get_form_kwargs(self, form_class):    kwargs = {'initial': self.get_initial()}    if self.request.method in ('POST', 'PUT'):        kwargs.update({            'data': self.request.POST,            'files': self.request.FILES,        })    return kwargs

django/views/generic/edit.py#L37

class FormMixin(ContextMixin):

post

get_form_kwargs

get_form_kwargs

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#70/82

POSTrequest

as_view

dispatch

post

def post(self, request, *args, **kwargs):    form_class = self.get_form_class()    form = self.get_form(form_class)    if form.is_valid():        return self.form_valid(form)    else:        return self.form_invalid(form)

django/views/generic/edit.py#L157

class ProcessFormView(View):

post

return super().post(request, *args, **kwargs)

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#71/82

POSTrequest

as_view

dispatch

post

return self.form_valid(form)

django/views/generic/edit.py#L123

def form_valid(self, form):    self.object = form.save()    return super(ModelFormMixin, self).form_valid(form)

class ModelFormMixin(FormMixin, SingleObjectMixin):

post

form_valid

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#72/82

POSTrequest

as_view

dispatch

post

return super().form_valid(form)

django/views/generic/edit.py#L61

def form_valid(self, form):        return HttpResponseRedirect(self.get_success_url())

post

form_valid

form_valid

class FormMixin(ContextMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#73/82

POSTrequest

as_view

dispatch

post

return HttpResponseRedirect(self.get_success_url())

django/views/generic/edit.py#L61

def get_success_url(self):    if self.success_url:        url = self.success_url % self.object.__dict__    else:        try:            url = self.object.get_absolute_url()        except AttributeError:            raise ImproperlyConfigured([...])    return url

post

...

get_success_url

class ModelFormMixin(FormMixin, SingleObjectMixin):

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#74/82

POSTrequest

as_view

dispatch

post

return self.post(request, *args, **kwargs)

def form_invalid(self, form):    return self.render_to_response(                        self.get_context_data(form=form))

django/views/generic/edit.py#L31

class FormMixin(ContextMixin):

post

form_invalid

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#75/82

CreateView

SingleObjectTemplateResponseMixinBaseCreateView

TemplateResponseMixin

ModelFormMixin ProcessFormView

FormMixin SingleObjectMixin

ContextMixin

View

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#76/82

Online resources

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#77/82

Digging Up Django Class-based Views

http://lgiordani.github.io/blog/categories/django/

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#78/82

Classy Class-Based Views: Django CBVs browser

http://ccbv.co.uk/

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#79/82

Django Vanilla Views

http://django­vanilla­views.org/

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#80/82

Class Based Views and Dry Ravioli

http://lukeplant.me.uk/blog/posts/class­based­

views­and­dry­ravioli/

Django's CBVs were a mistake

http://lukeplant.me.uk/blog/posts/djangos­cbvs­

were­a­mistake/

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#81/82

Some links to better understand Python OOP

http://www.reddit.com/r/Python/

comments/226ahl/some_links_about_python_oop/

About using the source code

http://blog.codinghorror.com/

learn­to­read­the­source­luke/

Leonardo Giordani - @tw_lgiordaniDjango class-based views – Survival guide for novices

#82/82

Thank you!Questions? Comments? Advice?

top related