Commits

Kenneth Love committed 1122c5c

added class-based-views doc

Comments (0)

Files changed (2)

docs/class_based_views.rst

+=================
+Class-Based Views
+=================
+
+The Old Way
+-----------
+
+You probably use one of these two ways for making a view that renders a form and then validates it on submit:
+
+::
+
+    @login_required
+    def awesome_view(request):
+        if request.method == "POST":
+            form = AwesomeForm(request.POST)
+
+            if form.is_valid():
+                form.save()
+                return HttpResponseRedirect(reverse('awesome'))
+            else:
+                form = AwesomeForm()
+
+        return render(“awesome.html”, {'form': form})
+
+Or:
+
+::
+
+    @login_required
+    def awesome_view(request):
+        form = AwesomeForm(request.POST or None)
+
+        if form.is_valid():
+            form.save()
+            return HttpResponseRedirect(reverse('awesome')
+
+        return render("awesome.html", {'form': form})
+
+These both work and they're fine but you often have to repeat yourself and you have to deal with ``if`` conditions when debugging. Not much fun, not very clean.
+
+The New Way
+-----------
+
+So, here's a class-based way of doing it:
+
+::
+
+    Class MyAwesomeView(TemplateView):
+        template_name = "awesome.html"
+
+        def get(self, request):
+            form = AwesomeForm()
+            return self.render_to_response({'form': form})
+
+        def post(self, request):
+            form = AwesomeForm(request.POST)
+            if form.is_valid():
+                form.save()
+                return HttpResponseRedirect(reverse('awesome'))
+
+            return self.render_to_response({'form': form})
+
+You have a ``template_name`` variable at the top that specifies the template for the view.
+
+Below that is the ``get()`` method that handles all ``GET`` requests. Typically it just takes ``self`` and ``request`` but if your route requires more arguments, they'll need to be specified here, too.
+
+And, surprise, surprise, below that is ``post()`` that takes care of your ``POST`` requests. Same arguments as ``get()`` since it has to be hit by the same route.
+
+What about @login_required?
+---------------------------
+
+True, we don't have ``@login_required`` on our methods and it won't work if you just add it there. What you can do, though, is wrap the ``dispatch()`` method and that will wrap all methods from that view with whatever 
+decorators you provide. Example below:
+
+::
+
+    @method_decorator(login_required)
+    def dispatch(self, *args, **kwargs):
+        return super(MyAwesomeView, self).dispatch(*args, **kwargs)
+
+Add this into your class and you should be safe from all those nasty unauthenticated users.
+
+URLs
+----
+
+How do you add these views to your URLs? Glad you asked:
+
+::
+
+    from project.views import MyAwesomeView
+
+    [...]
+    url(r’^awesome/$’, MyAwesomeView.as_view(), name=”awesome”)
+    [...]
+
+If you really hate having to import each view, at the bottom of your ``views.py`` file, you can do something like: ``awesome_view = MyAwesomeView.as_view()`` and then set your URLs view as ``app.awesome_view``. I don't 
+think this is needed, but to each his/her own.
+
+
+Thanks and I hope that helps everyone get a small grip on class-based views. There are many other class-based views available, such as ``FormView`` for handling form rendering and validation (so this entire method 
+wouldn't be needed) but there are very little docs for them. **Let's write them!**
+
    designers_make_it_go_to_eleven
 
    lightning_talks
+
+   class_based_views
    
 
 Indices and tables