write this less verbosely BUT - they are very inflexible. How many people have used a generic view, then almost immediately found they have to rewrite it? Now say we want to fetch our posts by thread id and slug...
return render_to_response(‘post_detail.html’, { ‘post’: post }) We’ve had to rewrite the functionality of our generic view. This could be even more complicated if we were using other generic view features Say this view is a view in a reusable application - we’ll have to rewrite it again to change a small bit of functionality
change: obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True if obj.author == request.user: return True else: return False admin.site.register(Book, BookAdmin) Customisability by subclassing the admin class and overriding a bunch of methods This is a simplified example - coincidently the same one Alex used in his talk earlier. It’s overriding a hook in the admin that only lets users edit objects they’ve created. Almost every decision made in the admin is done in a method that you can override. This means you don’t have to rewrite the whole admin just to add an extra bit of functionality
thread__pk=thread, slug=slug ) Now, say we want to extend it like we did before. We don’t have to rewrite the generic view, just override a method This is not a great example because its the same length as the simple function we had before. But - views in functions can get very hairy very quickly - you can see how this method will scale. You can even inherit from this class again to create a view with slightly different functionality There are also generic views like this for listing objects; creating, editing and deleting objects with forms; and listing objects within certain time periods. There are even views for just displaying something in a template, which all these views inherit from
context=None): template = env.select_template(names) return render_to_string( self.request, template, context) We can also do clever stuff. Mixins are really handy to alter the functionality of class-based views. This, for example, is a Mixin that makes any view render with Jinja instead of Django’s templates. TemplateView defines a method for rendering to a Django template. We can override this to render to a Jinja template instead
return self.get_response( self.get_resource(context), mimetype='application/json' ) return super(JsonMixin, self).render_to_response( names, context) Outputs JSON as well as templates given a format keyword argument from the URL Overriding a different method to the jinja example because we need to set the mimetype of the response, but the idea’s the same
def get_resource(self, context): return serializers.serialize('json', context['object_list']) Now we have a view that can output to JSON as well as templates. All the logic we’ve written to output data to templates can be reused. This could be used to write a really neat REST interface Many API tools for Django mean you have to use different URL namespaces, which isn’t RESTful
Post.objects.all() def get_resource(self, context): return serializers.serialize('json', context['object_list']) and of course - if we hook in our Jinja plugin to this view, we have a view that outputs to Jinja templates and JSON
the standard way of writing views. If everybody builds upon a single base view, cool stuff like Jinja mixins will work everywhere, including reusable apps That’s not saying we’re getting rid of the old way of writing views though - views are still just a callable that takes a request and a response
super(PostAdmin, self).get_urls() These class-based ideas can also be used for other things. One of my favourite things in the admin is that ModelAdmin is basically a class-based urlconf. You include the admin into a urlconf like you would include a urls.py. It lets you write urlconfs which can do clever routing, and subclass and extend them Example - newspaper sections
= '^$' Simon Willison did a similar thing with django openid, but with a neater API. You include a consumer into the urlconf like you include the admin interface, but it iterates over all the methods on itself and finds ones with a url regex defined. If somebody were to develop a generic way of writing class-based urlconfs, and set some conventions, it could be a really useful pattern. Maybe the urlconfs in Django core could be smarter too......
ticket 6735 has been around for almost 3 years. I’d like to cover some of the history of this and what we need to do to get this into Django core. As Eric mentioned yesterday, class-based views need conventions. Once it’s a part of Django, this will be the convention that views can be built upon. It started with Joseph’s patches, which had a number of people working on it, but was never finished. After 1.0, Jacob KM worked on it for 1.1, but again, never finished it. Since then, it has drifted, and the wheel has been reinvented many times.
details of implementing them have been argued over many flame wars on django-dev. It’s incredibly hard to decide on how it should work because it is one huge naming problem. It’s designing an API - choosing method names.