mirror of
https://expo.survex.com/repositories/expoweb/.git/
synced 2025-12-07 14:24:28 +00:00
document the _setup(), _get(), _post() structure for writing form-handling code - online edit of handbook/troggle/trogforms.html
This commit is contained in:
@@ -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. It’s 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>
|
||||
|
||||
Reference in New Issue
Block a user