Django Vanilla Views 1.0 released.
django-vanilla-views.org
django-vanilla-views.org
In my opinion, Django's CBV's are polarizing. Some people really love them as a way to reuse code (e.g. they are recommended glowingly in the popular Two Scoops of Django book) and people like me don't. I feel like inheritance is a poor way of modeling views and reusing code.
Whenever anyone voiced complaint about the CBV system, it usually was mixed in with complaints about the implementation of the generics. The response was always, "you don't have to use the generics provided, write your own." I'm really glad to see that Tom went exactly that route, and I'm happy that Django as a system is flexible enough to allow it. I may not be 100% convinced just yet but I'm willing to try this out and it seems like a definite step in the right direction to me. Nice work.
Thanks po - that's exactly the kind of response I was hoping for.
if request.method == "POST":
return render_request('template.html", params)It may not be revolutionary, but extending an UpdateView to block anonymous users and throwing a mixin that limit access to the objects the current user owns, I can have my "edit a blog post" view looking like:
class EditBlogPost(OwnedObjectsMixin, AuthenticatedUpdateView):
model = Blog
form = BlogForm
and all I have left to do is put my template, which is quite nice (especially when the List, Create, Delete views are about the same length in code).It gets less useful (and more convoluted) as your views get further away from basic CRUD stuff, but I still feel it's quite useful.
(Edited: the difference is more clear on the "Update" view)
@is_authenticated
@is_owner
def edit(self):
...A well-defined base CBV allows you to limit the use of RequestContexts, checks for method types, and special validations. For small projects it may not make a difference; for projects with at least couple dozen views and a bunch of common behavior, they increase readability tremendously.
Also, they offer a very good template for defining view behavior. Once you're familiarized with CBV method definitions it's much easier to grok code, as the view flow is much more standardized than for regular function views.
I occasionally see comments on threads claiming they are the best thing since sliced bread, but rarely can anyone back it up convincingly.
So, to me they feel like a fad, and should be avoided IMO.
I share your opinion on CBV. Personally I like the old function-based views because everything happens in that little block of code and I know exactly the order in which something happens. CBV quickly get me lost in the chain of method calls across classes.
I definitely hear you on inheritance. I'm becoming more convinced that inheritance in many cases is a crutch that prevents a much more reasonable control flow and maintainable design that can be achieved compositionally.
The mixing of inheritance and mixins in the canonical CBV design is tricky, to say the least. I guess it was done with the expectation that people would more directly use the mixins and base classes, but in reality, people tend to try to extend the leaf classes and the class tangle gets exacerbated. This project seems like a huge step in the right direction.
The goals of having a class based generic view was quite appealing with the possibility of leveraging inheritance and properties. But Mixins were probably the wrong way to achieve it. The Method Resolution Order can get very confusing leading to hard to resolve bugs. It seemed to be a very un-Pythonic ("If the implementation is hard to explain, it's a bad idea") implementation to me.
Also, after using them in a few projects, they reduce grokability and maintainability. Django's ORM is much more complex, but it operates at the right level of abstraction. CBVs always felt a bit too high level to work well. Going back and reading CBVs I wrote months ago always took more time than it feels like it should have.
That said, it took the ORM a while to get right, too, and the Django community is thoughtful when it comes to abstraction, and I'm sure views will land in a good spot.
Three key differentiators for me are the reduction in redundancy with CBVs, consist organization of code and better code reuse through inheritance. This comes out best with generic model views (as one poster has said).
The real problem with CBV generic view usage is that it's not very well-documented, specifically the order of method calls. I often have to refer to the source to understand the flow (which is fine, but a pain, and I imagine extremely intimidating for new users).
Were this well documented, I think it'd actually be easier for people to get into Django - because CBVs outline a lot of the key features that people would use in Django anyways, except now in a much more formal, easy-to-use way (i.e., get_context_data, Form submission and so forth).
In contrast, function views seem to be more for experts who need to do some kind of complicated view processing that goes beyond the bounds of a typical CRUD app.
"There are places where the generic views could/should be simplified, get_template_names and get_form_class are horrendously complicated. But his big example is removing get_form_kwargs, which is probably my single most heavily-used function when using them (Django's generic class-based views). Overriding form_valid is always a little gnarly, because you need to know the implementation details to know it's not worth calling super."
In general, I'm not sold on Tom's specific implementation, primarily because it throws away parts of the API that I personally use quite heavily. Of course, the counter-argument is that he's kept the parts that he uses heavily. I suspect the ideal solution is somewhere between Tom's implementation and the existing one.
The simple answer here is that you're actually much better off just overriding `get_form()`. It's no more complicated, and it's much more direct and obvious. We can do away with `get_form_kwargs()`, `get_initial()` etc - they're unnecessarily granular.
> you need to know the implementation details to know it's not worth calling super
The simplicity is self re-inforcing here - the implementation is trivial, so it's easy to figure out how to totally override a method if you want too. Of course this doesn't prevent you from using a `super` style if you want to.
We should fork django-extra-views and see what we can come up with.
Yup, that'd be interesting. Hopefully you've seen my comment to that effect here: http://django-vanilla-views.org/topics/django-extra-views-co...
if request.POST:
validate
save form
redirect to success page
else if request.GET:
show the form
Learning the views this way was very helpful when I barely understood how the internet worked. So naturally, when I took on an intern this year, I got her started with the Django tutorial, then gave her the above pseudocode as an example of how to write a simple form. After she worked on it for a while and got very confused, I looked over the Django 1.5 tutorial with her and saw those awful, overmagicked generic views they use now. I spent an hour trying to implement what would have taken me two minutes if the views were written manually, until I gave up and rewrote all of her code while standing on my soapbox.
Needless to say, I've been hoping for something like this project ever since.
I'll be curious to know what was the actual reasoning behind this complicated design.
It's only now that we've been using CBVs for a while that it's become more apparent that they're somewhat over-designed, and can be awkward to get to grips with.
- Django regular views are ok (though not class based)
- Django "class views" are a product of brain damage, really (see the example to see what I mean)
This looks like sane class based views, but I was expecting something more like the way Pyramid does it (which are not generic, but class based)
“Brain damage” is rather harsh: they're following a valid design principle but (IMO) carried a little further than the scope of the problem might require, running into the classic tradeoff versus ease of acquisition.
Interested to try out django vanilla views
The documentation source is markdown.
The styling and documentation building script is custom, and taken from the documentation for Django REST framework.
I'd like to build it into a proper markdown docs tool someday if I can find the time.
def form_valid(self, form):
send_activation_email(self.request.user)
account = form.save()It looks like that view which is a "CreateView" uses a ModelForm as its form. ModelForm's save methods return an instance of their Model.
In this case, account is the instance of the Account model which is created when that form is saved.
Edit - Here's the relevant Django doc: https://docs.djangoproject.com/en/dev/topics/forms/modelform...