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
Bruno Renié
June 04, 2012
Programming
9
1.6k
Class-based Views: patterns and anti-patterns
Bruno Renié
June 04, 2012
Tweet
Share
More Decks by Bruno Renié
See All by Bruno Renié
Visibility for web developers
brutasse
3
450
Decentralization & real-time with PubSubHubbub
brutasse
1
150
Deployability of Python Web Applications
brutasse
17
2.3k
Stop writing settings files
brutasse
21
2.6k
Packager son projet Django
brutasse
4
560
Staticfiles : tout ce qu'il faut savoir, rien que ce qu'il faut savoir
brutasse
4
540
Introduction to Django
brutasse
3
420
Other Decks in Programming
See All in Programming
JSONataを使ってみよう Step Functionsが楽しくなる実践テクニック #devio2025
dafujii
1
520
プロパティベーステストによるUIテスト: LLMによるプロパティ定義生成でエッジケースを捉える
tetta_pdnt
0
310
AIと私たちの学習の変化を考える - Claude Codeの学習モードを例に
azukiazusa1
9
3.7k
Updates on MLS on Ruby (and maybe more)
sylph01
1
180
開発チーム・開発組織の設計改善スキルの向上
masuda220
PRO
20
11k
複雑なドメインに挑む.pdf
yukisakai1225
5
1.1k
プロポーザル駆動学習 / Proposal-Driven Learning
mackey0225
2
1.2k
Vue・React マルチプロダクト開発を支える Vite
andpad
0
110
Kiroで始めるAI-DLC
kaonash
2
580
「待たせ上手」なスケルトンスクリーン、 そのUXの裏側
teamlab
PRO
0
500
機能追加とリーダー業務の類似性
rinchoku
2
1.2k
知っているようで知らない"rails new"の世界 / The World of "rails new" You Think You Know but Don't
luccafort
PRO
1
110
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
112
20k
Building an army of robots
kneath
306
46k
A Tale of Four Properties
chriscoyier
160
23k
RailsConf 2023
tenderlove
30
1.2k
Optimizing for Happiness
mojombo
379
70k
Designing Experiences People Love
moore
142
24k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Typedesign – Prime Four
hannesfritz
42
2.8k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
It's Worth the Effort
3n
187
28k
Why Our Code Smells
bkeepers
PRO
339
57k
Bash Introduction
62gerente
615
210k
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]