django-formset achieve batch operation data table

What is formset

We know that forms the component is used to make form validation, more correctly say, forms to verify the component is used to make a row of a database table. There are different forms assembly, and to verify the same family is formset multiple rows in the table, i.e. the components do formset bulk verification form.

Bulk add

Examples of the first formset object with the action table form class forms when object initialization parameter extrato display authentication data lines. Examples of the transferring object to the front page formset, two templates distal loop: loop form a first layer, the second layer in the form of a field cycle. When a GET request directly instantiated formset object to the front end. When POST request bulk verification form, when all the data is no problem, back-end database to save the data.

When you save data back, there are two ways: The first way is simple, but can not catch the error column unique constraint; therefore use formset is best to use the second batch add in the way data manually captured and handed over to the only constraint error message formset to the front page display.

  • models.Permission.objects.create(**row)
  • obj = models.Permission(**row) | obj.save()

The only constraint error process the captured information is required obj.validate_unique()to determine whether the object is the only constraint satisfied, if not abnormal by the capture operation to capture the abnormality information. Through formset.errors[i].update(e)to the wrong information into the formset front page display. We did so because they can not capture the unique constraint errors by verifying the forms component. So here were collected by hand and placed in an error message in forset.

In addition, if the front page rendering did not fill the form data submitted directly is not being given. formset default as long as the field does not change it will not do to verify the row data. Just fill in a field, the bank data will do form validation .

# views.py
def multi_add(request):
    """
    批量添加
    :param request:
    :return:
    """
    formset_class = formset_factory(MultiPermissionForm, extra=2)

    if request.method == 'GET':
        formset = formset_class()
        return render(request, 'multi_add.html', {'formset': formset})

    formset = formset_class(data=request.POST)
    if formset.is_valid():
        flag = True
        # 检查formset中没有错误信息,则讲用户提交的数据获取到。
        post_row_list = formset.cleaned_data  
        for i in range(0, formset.total_form_count()):
            row = post_row_list[i]
            if not row:
                continue
            try:
                obj = models.Permission(**row)
                obj.validate_unique()  # 检查当前对象在数据库是否存在唯一的异常。
                obj.save()
            except Exception as e:
                formset.errors[i].update(e)
                flag = False
        if flag:
            return HttpResponse('提交成功')
        else:
            return render(request, 'multi_add.html', {'formset': formset})
    return render(request, 'multi_add.html', {'formset': formset})

Two distal templates cycles: a first cycle formset to give each layer a form, that form a second layer to obtain each field cycle. As with forms using components, you need to add form submission form and input the number of buttons and csrf_token cross-domain request forgery manually. In addition, formset, also need to increase {{ formset.management_form }}, the use of which has increased formset which formset.management_form.

# multi_add.html
<form method="post">
    {% csrf_token %}
    {{ formset.management_form }}
    <table border="1">
        <thead>
        <tr>
            <th>标题</th>
            <th>URL</th>
            <th>NAME</th>
            <th>菜单</th>
            <th>父权限</th>
        </tr>
        </thead>
        <tbody>
        {% for form in formset %}
            <tr>
                {% for field in form %}
                    <td>{{ field }} <span style="color: red;">{{ field.errors.0 }}</span></td>
                {% endfor %}
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <input type="submit" value="提交">
</form>
Batch Edit

Batch Edit and increasing quantities of roughly the same, but there is a different use of the difference. When an object is instantiated formset default extra = 1, manually modify extra = 0; GET request, the page needs to display the default value, the internal data structure of a data dictionary listing nested assignment parameter initial. And the need to pass the id of each row of data, tells formset need to modify the data id . At this point forms the class to use as compared to the use of batch add one more class id field id = forms.IntegerField( widget=forms.HiddenInput()), a field hidden by default, the front page is not displayed.

The same will encounter unique constraint error, use of recycled and reflection for data update assignment for each field, and then submitted to the database save.

def multi_edit(request):
    formset_class = formset_factory(MultiUpdatePermissionForm, extra=0)
    if request.method == 'GET':
        formset = formset_class(
            initial=models.Permission.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id'))
        return render(request, 'multi_edit.html', {'formset': formset})

    formset = formset_class(data=request.POST)
    if formset.is_valid():
        # 检查formset中没有错误信息,则讲用户提交的数据获取到。
        post_row_list = formset.cleaned_data  
        flag = True
        for i in range(0, formset.total_form_count()):
            row = post_row_list[i]
            if not row:
                continue
            permission_id = row.pop('id')
            try:
                permission_object = models.Permission.objects.filter(id=permission_id).first()
                for key, value in row.items():
                    setattr(permission_object, key, value)
                permission_object.validate_unique()
                permission_object.save()

            except Exception as e:
                formset.errors[i].update(e)
                flag = False
        if flag:
            return HttpResponse('提交成功')
        else:
            return render(request, 'multi_edit.html', {'formset': formset})
    return render(request, 'multi_edit.html', {'formset': formset})

When the front-end templates cycle through each field, to determine whether it is the first id field, if it is the first directly {{field}}, the page will not be displayed.

<form method="post">
    {% csrf_token %}
    {{ formset.management_form }}
    <table border="1">
        <thead>
        <tr>
            <th>标题</th>
            <th>URL</th>
            <th>NAME</th>
            <th>菜单</th>
            <th>父权限</th>
        </tr>
        </thead>
        <tbody>
        {% for form in formset %}
            <tr>
                {% for field in form %}
                    {% if forloop.first %}
                        {{ field }}
                    {% else %}
                        <td>{{ field }} <span style="color: red;">{{ field.errors.0 }}</span></td>
                    {% endif %}
                {% endfor %}
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <input type="submit" value="提交">
</form>

Guess you like

Origin www.cnblogs.com/liuxu2019/p/11992573.html