Forms ===== The fundamental pattern for a view that handles a form is covered fully in the `Django form docs `_, so I don't have much to add, except a few notes: * You don't need to use ``FormView``, and I recommend you don't. * You don't actually need ``Form`` either. It's an API that provides a very helpful set of behaviours (validation etc.), but it's entirely possible to build forms in Django without it. You need to know how forms work at the `HTML level `_, and you need to process `request.GET `_ or `request.POST `_ yourself to get the submitted data and do something with it. Normally, this would be very tedious compared to using ``Form``, but in some cases it will be better. For example, if you have a page with dynamically generated controls (e.g. lots of buttons or input boxes) it can be easiest to build them up and process them without using ``Form``. * If you need multiple buttons on the same form, that do different things, you need to understand how this works at the HTML level. The button that is pressed becomes a “successful” control, which means the ``request.POST`` (or ``request.GET``) dictionary will get an entry with that control's ``name`` attribute. So it looks like this: Template: .. code-block:: html+django
{% csrf_token %} {{ form }}
View: .. code-block:: python def my_view(request): if request.method == 'POST': if 'preview' in request.POST: # Do preview thing... You may have to do something similar for multiple forms on one page. That's it! Next up: :doc:`preconditions`. Discussion: Complex form cases ------------------------------ Why not ``FormView``? Of all the CBVs, it is perhaps the most tempting, due to the control flow boilerplate that it eliminates. But overall, I still feel it is not worth it. First, it requires you to know and use a second API (``get_form_class``, ``form_valid``, ``get_initial`` etc.). All of these are more awkward to use than just using ``Form`` directly. It also makes some relatively common things much harder to do, and provides a very bad starting point for most customisations. For example, if you find you have a page that has two forms on it (perhaps alternative flows that the user can choose between), ``FormView`` will cause you lots of pain. Or if you have form handling as well as something else (such as a list of items), you will be in confusion if you are trying to use ``FormView``, even more so if you've forgotten how to use the ``Form`` API directly. Another example that comes up quite frequently, and described above, is when you need multiple different submit buttons which take different actions . This is an easy thing in HTML/HTTP, and easy if you are using ``Form`` directly and in charge of the control flow yourself, but horrible if you are trying to fit it into ``FormView``. Finally, the way that ``FormView`` obscures the flow control can be disastrous: In 2016 some Django core developers took on the task of refactoring a function based form view (the password reset views) to use ``FormView`` view. In the process, the checking of the “magic link” token was accidentally moved to a branch such that all security was effectively disabled — a trivial curl command enabled you to reset anyone’s password to anything you liked. Such a mistake would have been painfully obvious in the FBV, but in the CBV version, despite being authored by one core developer and reviewed by another, it went unnoticed and was committed to the master branch. It was `thankfully noticed `_ before the next release, but it highlights just how badly the use of mixins for flow control obscures your code and makes reasoning about it a nightmare.