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

Class Based Views: Untangling the Mess

Class Based Views: Untangling the Mess

Presentation from DjangoCon Europe 2014

One of the big changes in Django 1.3 was the introduction of Class-Based Views. Class-Based Views represent one of the biggest stylistic changes in Django since Magic Removal, and there's been lots of confusion surrounding them.

This talk will be a brief tutorial, providing some background and dispelling some of the confusion around the use of Class-Based Views. It will also look at some interesting possibilities that are made possible by the use of the class-based view framework.

Russell Keith-Magee

May 17, 2013
Tweet

More Decks by Russell Keith-Magee

Other Decks in Technology

Transcript

  1. In the beginning... • It’s 2005 • Django is for

    building websites • Views are for displaying content • There a lots of common patterns in views • We all like being DRY Thursday, 23 May 13
  2. Generic Views • Display a template • Display a single

    object • Display a list of objects • Display a form • Create, Update, Delete • Display a date archive Thursday, 23 May 13
  3. Example: Before def edit_book(request, book_id): try: book = Book.objects.get(pk=book_id) except

    Book.DoesNotExist: raise Http404 if request.method == ‘POST’: form = BookForm( instance=book, data=request.POST) if form.is_valid(): form.save() return HttpResponseRedirect( book.get_absolute_url()) ... Thursday, 23 May 13
  4. Problems • Configuration options limited by args • No control

    over logic flow • No re-use between views Thursday, 23 May 13
  5. What went wrong? • Fundamental confusion over purpose • Confusion

    over implementation choices • Ravioli Code • Bad documentation Thursday, 23 May 13
  6. Purpose • Two distinct, but connected bodies of work •

    Class Based Views • Class Based Generic Views Thursday, 23 May 13
  7. Class Based Views • A class based analog of a

    view function • Method-based HTTP-verb dispatch • ... and that’s it Thursday, 23 May 13
  8. Example from django.views.generic import View class MyView(View): def get(self, request,

    *args, **kwargs): return render(request, ‘myview.html’ {}) def post(self, request, *args, **kwargs): ... Thursday, 23 May 13
  9. Class Based Views • Automatic OPTIONS request handling • Automatic

    naïve HEAD request handling • Automatic HTTP 405 on unknown verbs Thursday, 23 May 13
  10. CB Generic Views • Uses Class Based View as a

    base • Creates analogs of the old generic views • Addresses limits of functional approach Thursday, 23 May 13
  11. What do you mean? urlpatterns = pattern(‘’, # Deploy the

    Class? (‘myview’, MyView), # or an Instance of a class (‘myview’, MyView()), # or a classmethod? (‘myview’, MyView.as_view), # or a Factory? (‘myview’, MyView.as_view()), ) Thursday, 23 May 13
  12. Problems • What is being instantiated? • How is it

    being instantiated? • When is this class instantiated? • How do you pass in configuration? • What is the lifespan of an instance? • What is the contract with urls.py? Thursday, 23 May 13
  13. Sidebar: Admin • Django’s admin is a class based view

    • Implemented using simple __call__() • Doesn’t have HTTP Verb support • Suffers from state problems Thursday, 23 May 13
  14. Solution • Factory classmethod • Returns function that invokes .dispatch()

    • initkwargs passed to __init__ • initkwargs must be pre-declared • view request, args and kwargs are stateful urlpatterns = pattern(‘’, (‘myview’, MyView.as_view( template_name=‘foo.html’)), ) Thursday, 23 May 13
  15. Sidebar: Other option • Change the urls.py contract • Currently:

    a callable • Change to: a callable or a class. • Decision: keep the urls.py contract clear Thursday, 23 May 13
  16. Ravioli • Goal: Replace function-based generics with class-based generics •

    Show what class-based approach can do • End point views built out of mixins Thursday, 23 May 13
  17. Mixins edit_view: get object if POST: get form if form

    is valid: handle form redirect else: handle failure else: get form return response Thursday, 23 May 13
  18. Mixins • UpdateView • BaseUpdateView • ModelFormMixin • FormMixin •

    SingleObjectMixin • ContextMixin • ProcessFormView • SingleObjectTemplate ResponseMixin • TemplateResponseMixin edit_view: get object if POST: get form if form is valid: handle form redirect else: handle failure else: get form return response Thursday, 23 May 13
  19. Mixins •CreateView •BaseCreateView • ModelFormMixin • FormMixin • SingleObjectMixin •

    ContextMixin • ProcessFormView • SingleObjectTemplate ResponseMixin • TemplateResponseMixin create_view: instantiate object if POST: get form if form is valid: handle form redirect else: handle failure else: get form return response Thursday, 23 May 13
  20. Mixins • CreateView • BaseCreateView • ModelFormMixin • FormMixin •

    SingleObjectMixin • ContextMixin • ProcessFormView •SingleObjectJSON ResponseMixin create_view: instantiate object if POST: get form if form is valid: handle form redirect else: handle failure else: get form return JSON response Thursday, 23 May 13
  21. Ravioli tastes good! • Allows for maximum reuse of core

    logic • Extremely flexible for inserting new logic • Easy to add your own mixins • But: You need to grok all the pieces Thursday, 23 May 13
  22. Documentation • Bad as originally released • Much better now

    • Still need framework decisions needed Thursday, 23 May 13
  23. Generic Views • Display a template • Display a single

    object • Display a list of objects • Display a form • Create, Update, Delete • Display a date archive Thursday, 23 May 13
  24. Modern problems • Multiple forms/formsets per page • Conditional forms

    • Continuous scrolling, not pagination • AJAX support (including in-place editing) • PJAX • Multiple “actions” per page Thursday, 23 May 13
  25. Call to action • In discussion: Do you mean CBV

    or CBGV? • Docs can still be improved • #18830 - FormCollection • Experiment with APIs. Django’s admin is a useful case study Thursday, 23 May 13