Hacker News new | past | comments | ask | show | jobs | submit login
Django Vanilla Views 1.0 released. (django-vanilla-views.org)
160 points by tomchristie on Sept 23, 2013 | hide | past | favorite | 42 comments



Contrary to somewhat popular belief, Django's function-based views are not deprecated and as far as I know, there are no plans to remove them. Django's class-based views were introduced and the generic views ported over to the CBV style (the older FBV versions were deprecated), however after giving it a go in a small part of our app, I found them to be overly-complex and hard to extend and went back to FBV.

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.


I've always liked CBV's, despite their complexity. Something just seemed more "right" about them than FBV's. That being said, the designers unquestionably got a bit class-happy, and it's almost impossible to use CBV's in any nontrivial way without dipping into the library source code (well written and documented as it may be) to truly understand the control flow between the overrides.

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.


I have been looking at them (but not using them) for a while because I cant see why I would want to re-use a view + it seem s like they require more work to implement then

if request.method == "POST":

   return render_request('template.html", params)


The basic concept doesn't make a big difference. The real meat is the generic model views, not the base CBV, imo.

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)


As opposed to two decorators on the blog module's edit method? I'm not sure a ClassView grants us any advantages for this use.

  @is_authenticated
  @is_owner
  def edit(self):
    ...


The decorator can only add behavior prior to the original function's execution, and many decorators may not necessarily be applied together. CBVs allow a composition of mixins that can include behavior that's substantially more complicated and can deal with any of the methods and members defined for the view.

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 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.

Thanks po - that's exactly the kind of response I was hoping for.


> In my opinion, Django's CBV's are polarizing [..] I feel like inheritance is a poor way of modeling views and reusing code.

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.


prior to asp.net mvc or those master page things, every asp.net project I ever worked on eventually had a base webform which was the dumping ground for everything and thus nightmarish to comprehend or maintain. Django's CBV's remind me of that nightmare and I tend to avoid them because it feels like reinventing a poorly designed wheel with no real value.

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.


This should be the standard. Today, I'd argue that class based generic views are the most complex part of Django to learn. The concern is usually met with rather blunt responses like 'read the source code' or 'try harder'.

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.


> I'd argue that class based generic views are the most complex part of Django to learn.

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.


I completely disagree with pundits that argue CBVs are way more complicated than function-based views.

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.


I'll paste my thoughts from a conversations I had with someone about them:

"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.


Hi Andrew, the migration notes cover the removal of `get_form_kwargs()`.

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.


There's something about your example that wasn't convincing to me, but I've tried it out with some of my use cases. Whilst your approach is less DRY, it does seem to lead to more readable code, so I'm going to look into it further.

We should fork django-extra-views and see what we can come up with.


> 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...


A little amusing that the only bits that work are the bits I've been regretting merging in :)


I started working with Django in 1.3.1 as my first REST framework. When I got to the views, it was easy to understand how the function responded to an HTTP request:

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.


Django class based views always seemed overly complicated to me. I cope with it thanks to the useful http://ccbv.co.uk/ and frequently had to hand draw the inheritance tree to understand what the hell was going on with my method calls.

I'll be curious to know what was the actual reasoning behind this complicated design.


I thought the design seemed reasonable at the time, the strict separation of concerns that the mixin classes provide is valid enough.

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.


Note to non-regular django devs: a django view is equivalent of the controller in other frameworks.


Not the case for Pyramid for example...


Interesting

- 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)


> Django "class views" are a product of brain damage, really

“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.


My experience has been that plain old function based views work out to be simpler and more flexible, at the cost of a little more duplication. Don't forget they are an alternative too!


Plus you can mix and match different view styles. If you have a lot of very similar views, elevate them to class-based views, or a smarter function-base view. If you have a lot of dissimilar views, you can keep them in function-based views while other parts of your app are using Vanilla Views or class-based views. Mix and match as appropriate (right tool, etc).


Completely agree. I don't know why people opt for CBV when you can refactor out the bits of function based views that are repeated, make them a function, and then use that function in your functional views. If you refactor enough, and name your functions well, you basically have a story for each view you can read from top to bottom that tells you exactly what it does.


I'm working on my first large scale programming project, learning Python and Django right now. I am in the midst of trying to figure out CBV's, and I am starting to understand and agree with the criticism of the generics that commenters have been making. If I want to make any modifications, I am finding myself just writing my view from scratch. I'm going to give this project a try today and see if it makes my life easier!


I personally don't find the regular CBV to be difficult to use and I prefer CBV to FBV in 99% of cases. I actually find it easy that the flow is separated into different methods, so that when I want to change a specific behavior, I don't have to read the whole view. That being said, I do find that I have to look at the source code for CBV from time to time, even though the documentation is quite good - but maybe "looking through source code" isn't quite as intimidating to me as to more beginner programmers.


I guess I'm in the minority - I really like the class based views for simple crud work. Obviously function based views are a better fit for things that are outside of the simple. but I've had a lot of luck using CBV to simplify crud work.

Interested to try out django vanilla views


Side comment: that's a nice website; how did you make it? I see it's hosted on GitHub pages and that you use Bootstrap. Did you write all the HTML/CSS yourself, or use Markdown, etc?


Thanks!

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.


Dear God, this. I started looking at your makedocs.py over the weekend myself. I've never liked rst.


In the example where does the account variable come from in the form_valid method?

def form_valid(self, form):

        send_activation_email(self.request.user)


        account = form.save()


Hiya, I think you've misread the example. The `account` variable doesn't come from anywhere outside the method. It's being instantiated right there.


If you look further down: http://django-vanilla-views.org/#inheritance-hierachy-django...

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...


This brings Django one step closer to including scaffolding (like Rails).


scaffolding doesn't require class based views ...


License isn't open. Pass.


Uh, whatcha talking about? It's a standard BSD 2-clause license.

http://opensource.org/licenses/BSD-2-Clause


Doh. My bad.


No problem :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: