Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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/

Leonardo Giordani

June 13, 2014
Tweet

More Decks by Leonardo Giordani

Other Decks in Programming

Transcript

  1. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #1/82 Django class-based views Survival guide for novices Leonardo Giordani @tw_lgiordani – lgiordani.github.com
  2. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #2/82 About me Leonardo Giordani http://lgiordani.github.io https://twitter.com/tw_lgiordani https://github.com/lgiordani https://plus.google.com/u/LeonardoGiordani Feel free to contact me Questions, suggestions, corrections are always warmly welcome
  3. Leonardo Giordani - @tw_lgiordani Django 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
  4. Leonardo Giordani - @tw_lgiordani Django 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?
  5. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #6/82 Django is a processor of HTTP requests Django HTTP REQUEST HTTP RESPONSE Django views
  6. Leonardo Giordani - @tw_lgiordani Django 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 URL dispatcher Template engine URL1 URL2
  7. Leonardo Giordani - @tw_lgiordani Django 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
  8. Leonardo Giordani - @tw_lgiordani Django 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
  9. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #10/82 Object-oriented programming Modularization Small components that may be easily changed Delegation Inheritance and composition allow heavy code reuse
  10. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #11/82 Class-based views from django.views.generic.list import ListView from articles.models import Article from django.conf.urls import url class ArticleListView(ListView): model = Article urlpatterns = [ url(r'^articles/$', ArticleListView.as_view()), ]
  11. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #12/82 from django.views.generic.list import ListView from articles.models import Article from 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.
  12. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #13/82 from django.views.generic.list import ListView from articles.models import Article from 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.
  13. Leonardo Giordani - @tw_lgiordani Django 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
  14. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #15/82 What happens behind the scenes?
  15. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #16/82 Use the source, Luke!* https://github.com/django/django * Jeff Atwood, 2012
  16. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #17/82 Source is a moving target https://github.com/django/django/tree/1.5.7
  17. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #18/82 @classonlymethod def 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()) GET request as_view class View(object):
  18. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #19/82 @classonlymethod def 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()) GET request as_view class View(object):
  19. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #20/82 GET request 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):
  20. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #21/82 GET request 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):
  21. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #22/82 GET request 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):
  22. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #23/82 GET request 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):
  23. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #24/82 GET request 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):
  24. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #25/82 GET request 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):
  25. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #26/82 GET request 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):
  26. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #27/82 GET request 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):
  27. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #28/82 GET request 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):
  28. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #29/82 GET request 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):
  29. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #30/82 GET request 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):
  30. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #31/82 GET request 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):
  31. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #32/82 GET request 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):
  32. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #33/82 GET request 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):
  33. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #34/82 GET request 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):
  34. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #35/82 GET request 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):
  35. Leonardo Giordani - @tw_lgiordani Django 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
  36. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #37/82 How do you customize CBVs behaviour?
  37. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #38/82 GET request as_view class ArticleListView(ListView): model = Article
  38. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #39/82 GET request 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
  39. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #40/82 GET request 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
  40. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #41/82 Arguments in class-based views
  41. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #42/82 @classonlymethod def 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()) GET request as_view class View(object):
  42. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #43/82 @classonlymethod def 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()) GET request as_view class View(object):
  43. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #44/82 GET request 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()),
  44. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #45/82 GET request 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()),
  45. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #46/82 GET request 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):
  46. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #47/82 GET request 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):
  47. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #48/82 GET request 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):
  48. Leonardo Giordani - @tw_lgiordani Django 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()) ]
  49. Leonardo Giordani - @tw_lgiordani Django 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
  50. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #51/82 ListView MultipleObjectTemplateResponseMixin BaseListView TemplateResponseMixin MultipleObjectMixin View ContextMixin
  51. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #52/82 ListView MultipleObjectTemplateResponseMixin BaseListView TemplateResponseMixin MultipleObjectMixin View ContextMixin as_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()
  52. Leonardo Giordani - @tw_lgiordani Django 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
  53. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #55/82 GET request 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):
  54. Leonardo Giordani - @tw_lgiordani Django 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
  55. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #57/82 What is the relationship between forms and HTTP methods?
  56. Leonardo Giordani - @tw_lgiordani Django 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
  57. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #59/82 from django.shortcuts import render from 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,})
  58. Leonardo Giordani - @tw_lgiordani Django 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
  59. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #61/82 POST request 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):
  60. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #62/82 POST request 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):
  61. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #63/82 POST request 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
  62. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #64/82 POST request 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)
  63. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #65/82 POST request 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()
  64. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #66/82 POST request 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)
  65. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #67/82 POST request 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
  66. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #68/82 POST request 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
  67. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #69/82 POST request 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
  68. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #70/82 POST request 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)
  69. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #71/82 POST request 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
  70. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #72/82 POST request 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):
  71. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #73/82 POST request 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):
  72. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #74/82 POST request 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
  73. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #75/82 CreateView SingleObjectTemplateResponseMixin BaseCreateView TemplateResponseMixin ModelFormMixin ProcessFormView FormMixin SingleObjectMixin ContextMixin View
  74. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #77/82 Digging Up Django Class-based Views http://lgiordani.github.io/blog/categories/django/
  75. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #78/82 Classy Class-Based Views: Django CBVs browser http://ccbv.co.uk/
  76. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #79/82 Django Vanilla Views http://django­vanilla­views.org/
  77. Leonardo Giordani - @tw_lgiordani Django 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/
  78. Leonardo Giordani - @tw_lgiordani Django 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/
  79. Leonardo Giordani - @tw_lgiordani Django class-based views – Survival guide

    for novices #82/82 Thank you! Questions? Comments? Advice?