document the _setup(), _get(), _post() structure for writing form-handling code - online edit of handbook/troggle/trogforms.html

This commit is contained in:
2025-10-27 12:40:29 +00:00
committed by Expo on server
parent 773f1ea174
commit caa08d4866

View File

@@ -9,8 +9,10 @@
<h4>Django Forms History</h4>
<p>Django has several generations of quite different clever mechanisms to make creating HTML forms "easier". Yes, making them might be easier, but maintaining this opinionated stuff is a nightmare without adequately educating yourself how the architecture works. This will take time: do not hurry.
<p>If you are a preofessional Django programmer, read <a href="https://www.loopwerk.io/articles/2025/django-views/?_bhlid=6ece59f0c3de24278c50871556723844d8ab734a">this article</a> for why Class Based Views are not a good fit for the community we have maintaining troggle.
<p>If you are a professional Django programmer, read <a href="https://www.loopwerk.io/articles/2025/django-views/?_bhlid=6ece59f0c3de24278c50871556723844d8ab734a">this article</a> for why Class Based Views are not a good fit for the community we have maintaining troggle:
<em>"Just look at the documentation of DetailView. To understand this one class,... 11 methods spread across 5 classes and mixins. Debugging a view or figuring out exactly which method to override to make the view behave in a certain way quickly becomes a case of opening way too many files and jumping back and forth between different method declarations. Its just too much".</em>
If you are still not convinced, read this <a href="https://spookylukey.github.io/django-views-the-right-way/index.html">much longer article</a>.
<p>WARNING: when reading the Django documentation on <a href="https://docs.djangoproject.com/en/5.1/topics/forms/">Forms</a> (unbound and <a href="https://docs.djangoproject.com/en/5.1/ref/forms/api/">bound</a>) and <a href="https://docs.djangoproject.com/en/dev/topics/forms/modelforms/">ModelForms</a>, do not get diverted into looking at Formsets or ModelFormsets. We do not use any formsets in troggle - of any kind[<a href="#bugger">*</a>].
<h3>Django 'Form' object</h3>
@@ -41,9 +43,50 @@ But if you haven't worked with HTML forms before, then you actually have <a href
<p>So that's enough to get you started. Now you are on your own, apart from help on the Website room of the Matrix chat and the nerd email list of course.
<h3>ModelForms</h3>
<h4>ModelForms</h4>
<p>A few of our data entry pages use <a href="https://docs.djangoproject.com/en/5.1/topics/forms/modelforms/">ModelForms</a>, these are where the Form object is automagically created from a Model class. If you can't find where something is initialised, it is probably because it was done automatically and invisibly by instantiating a ModelForm.
<h4>Form views: the code that handles form input</h4>
<p>The python code which handles the presentation of a form and handles the user responses is called a Django "View" and in troggle these functions are all in python files in the folder <var>troggle/core/views/</var>. There are two ways of doing it: Class-based views (CBV) and Function-based views (FBV). Troggle only uses function-based views for the reasons described very well in <a href="https://www.loopwerk.io/articles/2025/django-views/?_bhlid=6ece59f0c3de24278c50871556723844d8ab734a">this article</a> on why Class Based Views are not a good fit for the community we have maintaining troggle.
<p>The <a href="https://docs.djangoproject.com/en/5.2/topics/forms/#get-and-post">documented method</a> for handling the "GET" and "POST" http interactions in Django FBVs are to use a large if statement:
<pre><code>if request.method == "POST": # POST
....
else: # GET
....
</code></pre>
We use a different layout as these if statements can get very deep and long. We use a layout like this (simplified):
<pre><code>def dwgupload(request, folder):
def _setup(folder_arg):
# initialize common state and return context dictionary ctx
......
return ctx
def _get(ctx):
# build page and prepare form using data in the supplied context ctx
......
return ctx
def _post(ctx):
# handle POST -- validate form and save files, update ctx in-place
......
return ctx
# main flow: setup, then POST or GET handlers, then render
ctx = _setup(folder)
if request.method == "POST":
ctx = _post(ctx)
else:
ctx = _get(ctx)
response = render(request, .....) # rendered form to display on screen
</code></pre>
<p>
Not all our forms use this structure yet.
<p>
We looked at using the <a href="https://www.loopwerk.io/articles/2025/django-views/?_bhlid=6ece59f0c3de24278c50871556723844d8ab734a">extremely simplified Class-based View structure</a> where all our view functions would inherit from Django <var>View</var> class, but it has no advantages over this pure function structure and many disadvantages in readability and maintainability.
<h3 id="forloop">For loop</h3>
<figure class="onright">
<a href="../l/trogclass-1.html"><img src="../t/trogclass-2.jpg" ></a>