Class-based views with Django Simon Willison DJUGL, 7th April 2009
Transcript
1. Class-based views with Django Simon Willison DJUGL, 7th
April 2009
2. Reusability A guiding principle of Django Build
applications, not projects Generic views Thriving third party
ecosystem
3. The Django contract A Django view is a function that takes a
request object and returns a response object ORM, middleware,
template language, forms, authentication system, admin, sites etc
are all optional extras
4. Generic views Encapsulate common patterns in web development
List of things / page about each things Things that are archived by
date Things you can create/update/delete Lets look at the code for
object_detail
5. object_detail drawbacks You cant swap the ORM for something
else (without duck typing your own queryset) You have to use
RequestContext You cant modify something added to the context; you
can only specify extra_context Thats despite a great deal of effort
going in to making the behaviour customisable
6. newforms-admin De-coupled admin from the rest of Django
Admin is just another application A new approach to customisation
Powerful subclassing pattern
7. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
8. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
9. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
10. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
11. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
12. Finely grained permissions class Entry(models.Model): title
= models.CharField(max_length=255) author =
models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin):
exclude = ('author',) def queryset(self, request): queryset =
super(EntryAdmin, self).queryset(request) return
queryset.filter(author = request.user) def save_model(self,
request, obj, form, change): obj.author = request.user obj.save()
def has_change_permission(self, request, ojb=None): if not obj:
return True # access to change list return obj.author ==
request.user has_delete_permission = has_change_permission
admin.site.register(Entry, EntryAdmin)
13. Objects can be views A Django view is a function that takes
a request object and returns a response object A Django view is a
callable that takes a request object and returns a response
object
14. Objects can be views A Django view is a function that takes
a request object and returns a response object A Django view is a
callable that takes a request object and returns a response object
Just dene __call__() on the class
16. django_openid Next generation of my django-openid project
Taken a lot longer than I expected Extensive use of class-based
customisation
17. Ideas from django_openid Everything should go through a
render() method Every template inherits from base_template Every
decision should be a method Every form should come from a method
Every model interaction should live in a method
18. TemplateResponse If you render_to_response, a subclass cant
override and reuse your method while modifying the context or
template Solution: return TemplateResponse( request,
'article.html', context ) auth.py line 65
19. Class-based generic views Ticket #6735 Didnt quite make
1.1; scheduled for 1.2
20. Subclassable decorators ratelimitcache is a decorator that
implements rate limiting for a Django view Its a class disguised as
a function, using the __call__ method You can subclass it to
customise its behaviour
http://github.com/simonw/ratelimitcache/tree/master
21. Extending the contract Django view: take request / return
response Django middleware: take request / return response Django
application: take request / return response Django urlconf: take
request / return response Django site: take request / return
response