Transcript
Page 1: Django class-based views: survival guide for novices (v2)

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

Page 2: Django class-based views: survival guide for novices (v2)

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

Page 3: Django class-based views: survival guide for novices (v2)

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

Page 4: Django class-based views: survival guide for novices (v2)

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?

Page 5: Django class-based views: survival guide for novices (v2)

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

#5/82

What are Django views?

Page 6: Django class-based views: survival guide for novices (v2)

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

Page 7: Django class-based views: survival guide for novices (v2)

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

Page 8: Django class-based views: survival guide for novices (v2)

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

Page 9: Django class-based views: survival guide for novices (v2)

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

Page 10: Django class-based views: survival guide for novices (v2)

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

Page 11: Django class-based views: survival guide for novices (v2)

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

Page 12: Django class-based views: survival guide for novices (v2)

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.

Page 13: Django class-based views: survival guide for novices (v2)

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.

Page 14: Django class-based views: survival guide for novices (v2)

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

Page 15: Django class-based views: survival guide for novices (v2)

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

#15/82

What happens behind the scenes?

Page 16: Django class-based views: survival guide for novices (v2)

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

Page 17: Django class-based views: survival guide for novices (v2)

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

Page 18: Django class-based views: survival guide for novices (v2)

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):

Page 19: Django class-based views: survival guide for novices (v2)

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):

Page 20: Django class-based views: survival guide for novices (v2)

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):

Page 21: Django class-based views: survival guide for novices (v2)

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):

Page 22: Django class-based views: survival guide for novices (v2)

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):

Page 23: Django class-based views: survival guide for novices (v2)

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):

Page 24: Django class-based views: survival guide for novices (v2)

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):

Page 25: Django class-based views: survival guide for novices (v2)

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):

Page 26: Django class-based views: survival guide for novices (v2)

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):

Page 27: Django class-based views: survival guide for novices (v2)

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):

Page 28: Django class-based views: survival guide for novices (v2)

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):

Page 29: Django class-based views: survival guide for novices (v2)

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):

Page 30: Django class-based views: survival guide for novices (v2)

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):

Page 31: Django class-based views: survival guide for novices (v2)

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):

Page 32: Django class-based views: survival guide for novices (v2)

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):

Page 33: Django class-based views: survival guide for novices (v2)

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):

Page 34: Django class-based views: survival guide for novices (v2)

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):

Page 35: Django class-based views: survival guide for novices (v2)

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):

Page 36: Django class-based views: survival guide for novices (v2)

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

Page 37: Django class-based views: survival guide for novices (v2)

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

#37/82

How do you customize CBVs behaviour?

Page 38: Django class-based views: survival guide for novices (v2)

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

#38/82

GETrequest

as_view

class ArticleListView(ListView):    model = Article

Page 39: Django class-based views: survival guide for novices (v2)

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

Page 40: Django class-based views: survival guide for novices (v2)

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

Page 41: Django class-based views: survival guide for novices (v2)

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

#41/82

Arguments in class-based views

Page 42: Django class-based views: survival guide for novices (v2)

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):

Page 43: Django class-based views: survival guide for novices (v2)

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):

Page 44: Django class-based views: survival guide for novices (v2)

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

Page 45: Django class-based views: survival guide for novices (v2)

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

Page 46: Django class-based views: survival guide for novices (v2)

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):

Page 47: Django class-based views: survival guide for novices (v2)

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):

Page 48: Django class-based views: survival guide for novices (v2)

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):

Page 49: Django class-based views: survival guide for novices (v2)

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

Page 50: Django class-based views: survival guide for novices (v2)

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

Page 51: Django class-based views: survival guide for novices (v2)

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

#51/82

ListView

MultipleObjectTemplateResponseMixin BaseListView

TemplateResponseMixin MultipleObjectMixin View

ContextMixin

Page 52: Django class-based views: survival guide for novices (v2)

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

Page 53: Django class-based views: survival guide for novices (v2)

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

#53/82

CRUD operations and forms

Page 54: Django class-based views: survival guide for novices (v2)

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

Page 55: Django class-based views: survival guide for novices (v2)

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):

Page 56: Django class-based views: survival guide for novices (v2)

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

Page 57: Django class-based views: survival guide for novices (v2)

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

#57/82

What is the relationship between

forms and HTTP methods?

Page 58: Django class-based views: survival guide for novices (v2)

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

Page 59: Django class-based views: survival guide for novices (v2)

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

Page 60: Django class-based views: survival guide for novices (v2)

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

Page 61: Django class-based views: survival guide for novices (v2)

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):

Page 62: Django class-based views: survival guide for novices (v2)

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):

Page 63: Django class-based views: survival guide for novices (v2)

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

Page 64: Django class-based views: survival guide for novices (v2)

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)

Page 65: Django class-based views: survival guide for novices (v2)

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

Page 66: Django class-based views: survival guide for novices (v2)

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)

Page 67: Django class-based views: survival guide for novices (v2)

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

Page 68: Django class-based views: survival guide for novices (v2)

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

Page 69: Django class-based views: survival guide for novices (v2)

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

Page 70: Django class-based views: survival guide for novices (v2)

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)

Page 71: Django class-based views: survival guide for novices (v2)

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

Page 72: Django class-based views: survival guide for novices (v2)

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):

Page 73: Django class-based views: survival guide for novices (v2)

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):

Page 74: Django class-based views: survival guide for novices (v2)

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

Page 75: Django class-based views: survival guide for novices (v2)

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

#75/82

CreateView

SingleObjectTemplateResponseMixinBaseCreateView

TemplateResponseMixin

ModelFormMixin ProcessFormView

FormMixin SingleObjectMixin

ContextMixin

View

Page 76: Django class-based views: survival guide for novices (v2)

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

#76/82

Online resources

Page 77: Django class-based views: survival guide for novices (v2)

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/

Page 78: Django class-based views: survival guide for novices (v2)

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

#78/82

Classy Class-Based Views: Django CBVs browser

http://ccbv.co.uk/

Page 79: Django class-based views: survival guide for novices (v2)

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

#79/82

Django Vanilla Views

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

Page 80: Django class-based views: survival guide for novices (v2)

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/

Page 81: Django class-based views: survival guide for novices (v2)

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/

Page 82: Django class-based views: survival guide for novices (v2)

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

#82/82

Thank you!Questions? Comments? Advice?


Recommended