Django's in-line form set is just right for creating parent-child forms, such as the header part of a purchase order (date, customer name, etc.) and the order details (order, quantity, etc.) associated with it. is. (Handwriting example) However, it's a little confusing because you'll be dealing with multiple forms at once before you get used to it. Also, in the example of the purchase order, the line will have as many forms as the number set at the beginning for new input. However, if you run out of all the forms and want a new row, you have to implement the additional operation yourself. For that, jQuery is absolutely necessary.
In my case, I didn't understand the inline form set, and jQuery was about to be studied, so it didn't work as I expected and I had a hard time. It's easy once you understand everything. How can I add a row? I will share as much as I have learned.
Using jQuery as the subject of the order form, implement a button to add the form to the inline form set.
I won't explain the basics of Python and Django.
Let's start with a normal inline form set and see how Django manages a lot of forms. In the official tutorial, it's written around here [https://docs.djangoproject.com/en/3.0/topics/forms/formsets/) (Formset description, but form management is also inline formset It will be the same).
The source is put it here. Please enter the data of "Customer" and "Product" from the management screen.
The template to display the form is as follows. (Excerpt)
jutyu_form.html (excerpt)
<form action="" method="POST">
{{ form }}
<hr>
{{ formset.management_form }}
<div id="detail-area">
{% for detail in formset %}
{{ detail.as_table }}
<br>
{% endfor %}
</div>
{% csrf_token %}
<button class="btn btn-primary" type="submit">Save</button>
</form>
{{form}}
displays the "order date" and "customer" in the header part. The parts written in Django's template language are converted to HTML for web viewing. How is this part converted? Try viewing the page source in your browser.
Django has written a lot of things. ↓ (I added annotations, line breaks, etc.)
<!-- {{ form }}Contents of-->
<tr>
<th><label for="id_jutyu_date">Order date:</label></th>
<td>
<input type="text" name="jutyu_date" value="2020-07-02" required id="id_jutyu_date">
<input type="hidden" name="initial-jutyu_date" value="2020-07-02" id="initial-id_jutyu_date">
</td>
</tr>
<tr>
<th><label for="id_customer">client:</label></th>
<td>
<select name="customer" required id="id_customer">
<option value="" selected>---------</option>
<option value="1">Showa Kogyo</option>
<option value="2">Heisei Seisakusho</option>
</select>
</td>
</tr>
It seems that <label>
and <input>
are surrounded by <tr>
so that they are lined up horizontally.
Also, the initial value of the order date is recorded with the hidden attribute. The customer gave me a selece box without specifying anything. The initial value is unselected "---------".
Just write {{form}}
and it will be converted to the appropriate HTML. It will be very helpful.
But conversely, if you want to display something different from Django's conversion, for example, if you want a space instead of ":" at the end of the label name, or if you want the label and field to line up vertically, let's specify it in the template. There is no such thing, so I have to take another method.
Let's take a look at the inline form set part. The inline formset is instantiated in the view and passed to the template with the name'formset'.
This part of the template
{{ formset.management_form }}
<div id="detail-area">
{% for detail in formset %}
{{ detail.as_table }}
<br>
{% endfor %}
</div>
It was converted to HTML like this. ↓ (I added annotations, line breaks, etc.) It has increased considerably. It seems that the key to this theme is hidden in the information that is increasing in various ways.
<!-- {{ formaset.management_form }}Contents of-->
<input type="hidden" name="jutyudetail_set-TOTAL_FORMS" value="1" id="id_jutyudetail_set-TOTAL_FORMS">
<input type="hidden" name="jutyudetail_set-INITIAL_FORMS" value="0" id="id_jutyudetail_set-INITIAL_FORMS">
<input type="hidden" name="jutyudetail_set-MIN_NUM_FORMS" value="0" id="id_jutyudetail_set-MIN_NUM_FORMS">
<input type="hidden" name="jutyudetail_set-MAX_NUM_FORMS" value="1000" id="id_jutyudetail_set-MAX_NUM_FORMS">
<div id="detail-area">
<tr>
<th><label for="id_jutyudetail_set-0-part">parts:</label></th>
<td>
<select name="jutyudetail_set-0-part" id="id_jutyudetail_set-0-part">
<option value="" selected>---------</option>
<option value="1">111-222 /Stainless steel fittings</option>
<option value="2">333-444 /O-ring</option>
</select>
</td>
</tr>
<tr>
<th><label for="id_jutyudetail_set-0-quantity">Order quantity:</label></th>
<td><input type="number" name="jutyudetail_set-0-quantity" id="id_jutyudetail_set-0-quantity"></td>
</tr>
<tr>
<th><label for="id_jutyudetail_set-0-DELETE">Delete:</label></th>
<td>
<input type="checkbox" name="jutyudetail_set-0-DELETE" id="id_jutyudetail_set-0-DELETE">
<input type="hidden" name="jutyudetail_set-0-id" id="id_jutyudetail_set-0-id">
<input type="hidden" name="jutyudetail_set-0-jutyu_head" id="id_jutyudetail_set-0-jutyu_head">
</td>
</tr>
<br>
</div>
It is written in HTML created from {{formset.management_form}}
.
<input type="hidden" name="jutyudetail_set-TOTAL_FORMS" value="1" id="id_jutyudetail_set-TOTAL_FORMS">
It has a hidden attribute <input>
with a long id. This line shows the number of forms in the inline form set, where value =" 1 "
is. In this case it is one line.
What about each field? For example, the HTML of the select box for selecting a part looks like this.
<tr>
<th><label for="id_jutyudetail_set-0-part">parts:</label></th>
<td>
<select name="jutyudetail_set-0-part" id="id_jutyudetail_set-0-part">
<option value="" selected>---------</option>
<option value="1">111-222 /Stainless steel fittings</option>
<option value="2">333-444 /O-ring</option>
</select>
</td>
</tr>
It consists of <label>
and <select>
and has a common id and name attribute. Looking at id, it means something like this.
It seems to be long, but it is regular. The name attribute just doesn't have an'id_'.
The ** id_jutyudetail_set-** part was also used in TOTAL_FORMS. This is the original model ** Jutyu Detail ** in all lowercase. That is the set.
Also, I found out earlier that the number of forms included in the inline form set is one. The numbers are numbered from 0, so it's the 0th of the form, its ** part ** field.
Then, what is the id that should be given to the order quantity field when adding a second form, which is not yet available?
What is the id of the order quantity field in the second form?
id="id_jutyudetail_set-0-quantity"
If so, it looks good.
Django has added two hidden attributes.
<input type="hidden" name="jutyudetail_set-0-id" id="id_jutyudetail_set-0-id">
<input type="hidden" name="jutyudetail_set-0-jutyu_head" id="id_jutyudetail_set-0-jutyu_head">
Looking at ʻid = , it is the id of the JutyuDetail model and the jutyu_head of the foreign key field. I used
{{detail_form.as_table}}` in the template for the sake of simplicity, because Django generated the HTML, including the fields that aren't displayed.
The line you add does not need to include these two.
If you write the procedure to add a line in words,
Now suppose you get the value of TOTAL_FORMS and it is 3. There are 0, 1 and 2 forms. The newly added form will have the id of ʻid_jutyudetail_set-3-field name`.
I'm sorry. I'm studying jQuery and I'm not confident, but I can write it as follows.
{% block extrajs %}
<script>
jQuery(function ($) {
// 1.Get the number of forms included in the inline form set (= TOTAL)_Get the FORMS value)
var totalManageElement = $("input#id_jutyudetail_set-TOTAL_FORMS");
var currentJutyuDetailCount = parseInt(totalManageElement.val());
//When the "Add Row" button is pressed
//2. Add each field with an id containing a number to indicate the number
$("button#addForm").on("click", function () {
//parts
var partElement = $("<select>", {
name: "jutyudetail_set-" + currentJutyuDetailCount + "-part",
id: "id_jutyudetail_set-" + currentJutyuDetailCount + "-part",
});
partElement.append($("<option>").html("---------").val(""));
{% for part in part_list %}
partElement.append($("<option>").html("{{ part }}").val("{{ part.pk }}"));
{% endfor %}
//Order quantity
var quantityElement = $("<input>", {
type: "number",
name: "jutyudetail_set-" + currentJutyuDetailCount + "-quantity",
id: "id_jutyudetail_set-" + currentJutyuDetailCount + "-quantity",
});
//Delete
var deleteElement = $("<input>", {
type: "checkbox",
name: "jutyudetail_set-" + currentJutyuDetailCount + "-DELETE",
id: "id_jutyudetail_set-" + currentJutyuDetailCount + "-DELETE",
});
//add to
$(partElement).appendTo("div#detail-area");
$(quantityElement).appendTo("div#detail-area");
$(deleteElement).appendTo("div#detail-area");
$("<br>").appendTo("div#detail-area");
// 3. TOTAL_Increase FORMS by 1
currentJutyuDetailCount += 1
$("input#id_jutyudetail_set-TOTAL_FORMS").attr("value", currentJutyuDetailCount);
});
});
</script>
{% endblock extrajs %}
Label display is omitted. It's also noisy that every line is labeled. If you actually use it, you should think about the form design itself.
For the time being, I have something that works. However, if there are more fields, it is quite troublesome to write. It needs to be rewritten even if the order of the fields changes. There should be an easier way, just because I don't know, so I'll write about that again.
--Narito Blog "Django implements add form button in form set"
Recommended Posts