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
技術的負債で信頼性が限界だったWordPress運用をShifterで完全復活させた話
rvirus0817
1
1.9k
サイトを作ったらNFCタグキーホルダーを爆速で作れ!
yuukis
0
390
Understanding Ruby Grammar Through Conflicts
yui_knk
1
120
ゲームの物理
fadis
5
1.2k
エンジニアのための”最低限いい感じ”デザイン入門
shunshobon
0
120
コンテキストエンジニアリングで変わるAI活用 リファクタリングワークフローの実践から学んだ形式知
leveragestech
0
100
新しいモバイルアプリ勉強会(仮)について
uetyo
1
260
Amazon Q CLI開発で学んだAIコーディングツールの使い方
licux
3
190
Vibe coding コードレビュー
kinopeee
0
450
KessokuでDIでもgoroutineを活用する / Go Connect #6
mazrean
0
100
AIレビュアーをスケールさせるには / Scaling AI Reviewers
technuma
2
200
The state patternの実践 個人開発で培ったpractice集
miyanokomiya
0
130
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
Faster Mobile Websites
deanohume
309
31k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
61k
Embracing the Ebb and Flow
colly
86
4.8k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
560
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Balancing Empowerment & Direction
lara
2
580
Docker and Python
trallard
45
3.5k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
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]