Class Based Views:
Past, Present and Future
Dr Russell Keith-Magee
DjangoCon AU 2014
Slide 2
Slide 2 text
No content
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
Class Based Views
Slide 5
Slide 5 text
In the beginning...
Slide 6
Slide 6 text
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
Slide 7
Slide 7 text
No content
Slide 8
Slide 8 text
Generic Views
• Display a template
• Display a single object
• Display a list of objects
• Display a form
• Create, Update, Delete
• Display a date archive
Slide 9
Slide 9 text
Key features
• Each view is a function
• Configuration via arguments
Slide 10
Slide 10 text
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())!
...
Slide 11
Slide 11 text
Example: Before
...!
else:!
form = BookForm(instance=obj)!
return render(request, 'edit_book.html', {!
'book': book!
'form': form!
})!
Ravioli
• Goal: Replace function-based generics with
class-based generics
• Show what class-based approach can do
• End point views built out of mixins
Slide 30
Slide 30 text
freakboy3742’s
Ravioli Cooking 101
Slide 31
Slide 31 text
Mixins
def edit_view():
get object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 32
Slide 32 text
Mixins
• UpdateView
• BaseUpdateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectTemplate
ResponseMixin
• TemplateResponseMixin
def edit_view():
get object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 33
Slide 33 text
Mixins
• UpdateView
• BaseUpdateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectTemplate
ResponseMixin
• TemplateResponseMixin
def edit_view():
get object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 34
Slide 34 text
Mixins
• UpdateView
• BaseUpdateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectTemplate
ResponseMixin
• TemplateResponseMixin
def edit_view():
get object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 35
Slide 35 text
Mixins
• UpdateView
• BaseUpdateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectTemplate
ResponseMixin
• TemplateResponseMixin
def edit_view():
get object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 36
Slide 36 text
Mixins
• CreateView
• BaseCreateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectTemplate
ResponseMixin
• TemplateResponseMixin
def create_view():
instantiate object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return response
Slide 37
Slide 37 text
Mixins
• CreateView
• BaseCreateView
• ModelFormMixin
• FormMixin
• SingleObjectMixin
• ContextMixin
• ProcessFormView
• SingleObjectJSON
ResponseMixin
def create_view():
instantiate object
if POST:
get form
if form is valid:
handle form
redirect
else:
handle failure
else:
get form
return JSON response
Example: After CBGV
from django.views import generic!
!
!
!
!
urlpatterns = patterns('',!
url(!
r'^/book/(?P\d+)/$',!
generic.UpdateView.as_view(model=Book),!
name='edit-book'!
)!
...!
Slide 40
Slide 40 text
Example: After CBGV
from django.views import generic!
!
class BookUpdateView(generic.UpdateView):!
model = Book!
!
urlpatterns = patterns('',!
url(!
r'^/book/(?P\d+)/$',!
BookUpdateView.as_view(),!
name='edit-book'!
)!
...!
Slide 41
Slide 41 text
Example: After CBGV
class BookUpdateView(generic.UpdateView):!
model = Book!
!
def form_valid(self, form):!
self.object.process()!
return super(BookUpdateView, !
self).form_valid(form)!
Slide 42
Slide 42 text
Example: After CBGV
from random import random!
!
class PermissionsMixin(object):!
def get_object(self, queryset=None):!
if random() > 0.8:!
raise Http404('Better luck next time')!
else:!
return super(PermissionsMixin, !
self).get_object(queryset)!
!
class BookUpdateView(PermissionsMixin,!
generic.UpdateView):!
model = Book!
Slide 43
Slide 43 text
Ravioli tastes good!
• Allows for reuse of core logic
• Extremely flexible for inserting new logic
• Easy to add your own mixins
• But: You need to grok all the pieces
Slide 44
Slide 44 text
Documentation
• Bad as originally released
• Much better now
• ccbv.co.uk
• Still need framework decisions needed
Slide 45
Slide 45 text
Where to from here?
Slide 46
Slide 46 text
Have we solved the
wrong problem?
Slide 47
Slide 47 text
Generic Views
• Display a template
• Display a single object
• Display a list of objects
• Display a form
• Create, Update, Delete
• Display a date archive
Slide 48
Slide 48 text
Modern web sites
have different problems
Slide 49
Slide 49 text
Modern problems
• Multiple forms/formsets per page
• Continuous scrolling, not pagination
• AJAX support (including in-place editing)
• PJAX
• Multiple “actions” per page
• Rich, Javascript-driven UI
Slide 50
Slide 50 text
API-driven UI
• A modern web site is an API with a UI
• A user interface is:
• a way to get meat to invoke an API
• a way to visualize API results
Slide 51
Slide 51 text
API-driven UI in Django
• APIs are easy
• DRF, TastyPie and others.
• Still need “views”
• Navigation
• Composition
Slide 52
Slide 52 text
All of this requires a
strong base framework
Slide 53
Slide 53 text
Class-Based Views
provide that framework
Slide 54
Slide 54 text
django.contrib.admin
• Django’s admin is a class based view
• Implemented using simple __call__()
• Doesn’t have HTTP Verb support
• Suffers from state problems
Slide 55
Slide 55 text
Doesn’t need to be
part of Django core
Slide 56
Slide 56 text
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