Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Class-based Views: patterns and anti-patterns
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Bruno Renié
June 04, 2012
Programming
1.7k
9
Share
Class-based Views: patterns and anti-patterns
Bruno Renié
June 04, 2012
More Decks by Bruno Renié
See All by Bruno Renié
Visibility for web developers
brutasse
3
470
Decentralization & real-time with PubSubHubbub
brutasse
1
170
Deployability of Python Web Applications
brutasse
17
2.4k
Stop writing settings files
brutasse
21
2.6k
Packager son projet Django
brutasse
4
580
Staticfiles : tout ce qu'il faut savoir, rien que ce qu'il faut savoir
brutasse
4
580
Introduction to Django
brutasse
3
440
Other Decks in Programming
See All in Programming
Feature Toggle は捨てやすく使おう
gennei
0
520
仕様漏れ実装漏れをなくすトレーサビリティAI基盤のご紹介
orgachem
PRO
9
5.4k
Nuxt Server Components
wattanx
0
260
PHPで TLSのプロトコルを実装してみる
higaki_program
0
750
実践CRDT
tamadeveloper
0
430
Reactive ❤️ Loom: A Forbidden Love Story
franz1981
2
230
PHP 7.4でもOpenTelemetryゼロコード計装がしたい! / PHPerKaigi 2026
arthur1
1
550
PHP で mp3 プレイヤーを実装しよう
m3m0r7
PRO
0
230
「話せることがない」を乗り越える 〜日常業務から登壇テーマをつくる思考法〜
shoheimitani
4
690
Xdebug と IDE による デバッグ実行の仕組みを見る / Exploring-How-Debugging-Works-with-Xdebug-and-an-IDE
shin1x1
0
360
おれのAgentic Coding 2026/03
tsukasagr
1
140
Oxlintとeslint-plugin-react-hooks 明日から始められそう?
t6adev
0
110
Featured
See All Featured
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
690
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
490
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
500
Making Projects Easy
brettharned
120
6.6k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.5k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.3k
Context Engineering - Making Every Token Count
addyosmani
9
810
Building a Scalable Design System with Sketch
lauravandoore
463
34k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
66k
Chasing Engaging Ingredients in Design
codingconduct
0
170
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
110
Transcript
Bruno Renié djangocon.eu 2012 Class-based Views patterns & anti-patterns
New in Django 1.3 Better in Django 1.4
Controversy http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/ http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html
The view contract in Django
# Your code def view(request): return HttpResponse('yay') urlpatterns = patterns('',
r'^$', view) # Django callback, args, kwargs = resolve(request.path_info) response = callback(request, *args, **kwargs)
A view is a callable that takes a request and
returns a response
Deprecation function-based generic views are being deprecated function-based views aren't
going anywhere
Other class-based stuff
class Middleware(object): def process_request(self, request): ... Middleware
class PageAdmin(admin.ModelAdmin): def get_changelist(self, request, **kwargs): ... Admin
single instance shared across requests
from django.views import generic class Users(generic.ListView): ... users = Users.as_view()
CBV api
as_view()?
class View(object): @classonlymethod def as_view(cls, **init): def view(request, *args, **kwargs):
self = cls(**init) return self.dispatch(request, *args, **kwargs) return view
class View(object): @classonlymethod def as_view(cls, **init): def view(request, *args, **kwargs):
self = cls(**init) return self.dispatch(request, *args, **kwargs) return view Thread-safety self.request self.args self.kwargs
Declarative vs. imperative
ccbv.co.uk
(biased) usage tips
Keep urls.py for URL definition Decorate in views.py
from django.utils.decorators import method_decorator def cbv_decorator(decorator): def _decorator(cls): cls.dispatch =
method_decorator(decorator)(cls.dispatch) return cls return _decorator @cbv_decorator(login_required) class MyView(generic.ListView): pass Decorating
Decorating class MyView(generic.ListView): pass my_view = MyView.as_view() my_view = login_required(my_view)
Decorating from django.views.decorators.cache import cache_page class CacheMixin(object): cache_timeout = 60
def dispatch(self, *args, **kwargs): return cache_page(self.cache_timeout)( super(CacheMixin, self).dispatch )(*args, **kwargs) class CachedView(CacheMixin, ListView): cache_timeout = 100 @cyberdelia — https://gist.github.com/1231560
MRO Extend, don't override unless you're 100% sure of what
you're doing
class MyView(generic.FormView): def get_initial(self): initial = super(MyViews, self).get_initial() initial.update({ 'foo':
'bar', 'other': 'thing', }) return initial
Case studies
Form processing class MyView(generic.FormView): def get_form_kwargs(self): kw = super(MyView, self).get_form_kwargs()
kw['user'] = self.request.user return kw def form_valid(self, form): form.save() return super(MyView, self).form_valid(form)
Form processing class MyForm(forms.Form): def __init__(self, *args, **kwargs): self.user =
kwargs.pop('user') super(MyForm, self).__init__(*args, **kwargs) def save(self): # self‐contained, user is known
Nested navigation class Level1(generic.TemplateView): template_name = 'level_1.html' def get_context_data(self, **kwargs):
ctx = super(Level1, self).get_context_data(**kwargs) ctx['stuff'] = do_some_work() return ctx class Level2(Level1): template_name = 'level2.html' def get_context_data(self, **kwargs): ctx = super(Level2, self).get_context_data(**kwargs) ctx['other_stuff'] = level_2_work() return ctx
Drop-in features class CleverPaginator(object): paginate_by = 100 def get_count(self): raise
NotImplementedError def get_paginate_by(self, queryset): count = self.get_count() if count > self.paginate_by * 1.5: return self.paginate_by return count class CountryView(CleverPaginator, ListView): def get_count(): return self.country.num_people
Registration
django-registration is great, but… I want more template variables I'm
not using contrib.auth I want to send an SMS instead of an email …
Writing a custom backend is not as simple as subclassing
the default views from le_social.registration import views class Register(views.Register): form_class = SMSRegistrationForm def send_notification(self): ... Sane, easily overridable defaults pip install django-le-social
Settings
Does it have to be that global? Is it a
switch people will want to flip at any time? Could it be… a class attribute/method instead? I know, I'll add a setting
ACCOUNT_EXPIRES_IN from le_social.registration import views class Activate(views.Activate): expires_in = 3600
* 24 * 7 # 7 days
SOCIAL_AUTH_LOGIN_REDIRECT_URL SOCIAL_AUTH_BACKEND_ERROR_URL from le_social.twitter import views class Callback(views.Callback): def success(self,
auth): ... def error(self, message): ...
CBVs are great but don't use them for everything
class Handler500(generic.TemplateView): template_name = '500.html'
None
class View(object): def dispatch(self, request, *args, **kwargs): handler = getattr(self,
request.method.lower(), self.http_method_not_allowed) return handler(request, *args, **kwargs)
Fantastic API for shipping reusable views Good API for extending
and plugging features in existing code
As a FBGV replacement: more power, less simplicity Don't limit
yourself to Django's implementation. Use the base View and your creativity
@brutasse
[email protected]