$30 off During Our Annual Pro Sale. View Details »

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. Class Based Views:
    Untangling the Mess
    Dr Russell Keith-Magee
    DjangoCon Europe 2013
    Thursday, 23 May 13

    View Slide

  2. Thursday, 23 May 13

    View Slide

  3. Thursday, 23 May 13

    View Slide

  4. Class Based Views
    Thursday, 23 May 13

    View Slide

  5. In the beginning...
    Thursday, 23 May 13

    View Slide

  6. 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

    View Slide

  7. Thursday, 23 May 13

    View Slide

  8. 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

    View Slide

  9. Key features
    • Each view is a function
    • Configuration via arguments
    Thursday, 23 May 13

    View Slide

  10. 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

    View Slide

  11. Example: Before
    ...
    else:
    form = BookForm(instance=obj)
    return render(request, ‘edit_book.html’, {
    ‘book’: book
    ‘form’: form
    })
    Thursday, 23 May 13

    View Slide

  12. Example: Before
    urlpatterns = patterns('',
    url(
    r’^/book/(?P\d+)/$’,
    book_view,
    name=‘edit-book’
    )
    ...
    Thursday, 23 May 13

    View Slide

  13. Example: After
    urlpatterns = patterns('',
    url(
    r’^/book/(?P\d+)/$’,
    generic.update_object, {‘model’: Book,},
    name=‘edit-book’
    )
    ...
    Thursday, 23 May 13

    View Slide

  14. Example: After
    urlpatterns = patterns('',
    url(
    r’^/author/(?P\d+)/$’,
    generic.update_object, {‘model’: Author,},
    name=‘edit-author’
    )
    ...
    Thursday, 23 May 13

    View Slide

  15. Problems
    • Configuration options limited by args
    • No control over logic flow
    • No re-use between views
    Thursday, 23 May 13

    View Slide

  16. Thursday, 23 May 13

    View Slide

  17. Let’s go class-based!
    Thursday, 23 May 13

    View Slide

  18. Django 1.3
    Thursday, 23 May 13

    View Slide

  19. OMFGBBQ!!1!!
    Thursday, 23 May 13

    View Slide

  20. What went wrong?
    • Fundamental confusion over purpose
    • Confusion over implementation choices
    • Ravioli Code
    • Bad documentation
    Thursday, 23 May 13

    View Slide

  21. Purpose
    • Two distinct, but connected bodies of work
    • Class Based Views
    • Class Based Generic Views
    Thursday, 23 May 13

    View Slide

  22. Class Based Views
    • A class based analog of a view function
    • Method-based HTTP-verb dispatch
    • ... and that’s it
    Thursday, 23 May 13

    View Slide

  23. 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

    View Slide

  24. Class Based Views
    • Automatic OPTIONS request handling
    • Automatic naïve HEAD request handling
    • Automatic HTTP 405 on unknown verbs
    Thursday, 23 May 13

    View Slide

  25. 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

    View Slide

  26. Implementation choices
    https://code.djangoproject.com/wiki/ClassBasedViews
    Thursday, 23 May 13

    View Slide

  27. Obvious choice
    • A class that is instantiated as a view
    Thursday, 23 May 13

    View Slide

  28. 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

    View Slide

  29. 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

    View Slide

  30. 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

    View Slide

  31. 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

    View Slide

  32. 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

    View Slide

  33. 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

    View Slide

  34. freakboy3742’s
    Ravioli Cooking 101
    Thursday, 23 May 13

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. 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

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. Documentation
    • Bad as originally released
    • Much better now
    • Still need framework decisions needed
    Thursday, 23 May 13

    View Slide

  41. Where to from here?
    Thursday, 23 May 13

    View Slide

  42. Have we solved the
    wrong problem?
    Thursday, 23 May 13

    View Slide

  43. 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

    View Slide

  44. Modern web sites
    have different problems
    Thursday, 23 May 13

    View Slide

  45. 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

    View Slide

  46. 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

    View Slide

  47. Questions?
    http://djangoproject.org
    http://cecinestpasun.com
    [email protected]
    @freakboy3742
    Thursday, 23 May 13

    View Slide