form组件之formset实现批量添加和编辑

2022/2/12 23:44:57

本文主要是介绍form组件之formset实现批量添加和编辑,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

示例效果:

 

 

 

 

 

 form组件或ModelForm组件用于做一个表单验证,formset是用于做多个表单验证的组件。

formset/settings.py

LANGUAGE_CODE = 'zh-hans'
# 把报错信息改为中文

formset/urls.py

from django.contrib import admin
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^multi_add/$', views.multi_add, name="multi_add"),
    re_path(r'^multi_edit/$', views.multi_edit, name="multi_edit"),
    re_path(r'', views.multi_add),
]

app01/models.py

from django.db import models

# Create your models here.


class Menu(models.Model):
    """一级菜单表"""
    title = models.CharField(
        verbose_name="一级菜单名称",
        max_length=32,
    )
    icon = models.CharField(
        verbose_name="图标",
        max_length=64,
        # null=True,  # 表示数据库中可以为空
        # blank=True,  # admin后台管理中可以输入为空
    )

    def __str__(self):
        return self.title


class Permission(models.Model):
    """权限表"""
    title = models.CharField(
        verbose_name="权限名称",
        max_length=32,
    )
    url = models.CharField(
        verbose_name="含正则URL",
        max_length=128,
    )
    name = models.CharField(
        verbose_name="URL别名",
        max_length=32,
        unique=True,
    )
    menu = models.ForeignKey(
        to="Menu",
        on_delete=models.CASCADE,
        verbose_name="所属二级菜单",
        null=True,  # 并不是所有的url都可以做二级菜单,所以这里需要设置null=True
        blank=True,
        help_text="null表示不是二级菜单,非null表示是二级菜单",
    )
    pid = models.ForeignKey(
        verbose_name="关联的权限",
        to="Permission",
        null=True,  # 如果是二级菜单,那么此字段为空,非二级菜单此字段不为空
        blank=True,
        on_delete=models.CASCADE,
        help_text="对于非菜单权限需要选择一个可以成为菜单的权限,用于做默认展开和选中菜单",
        related_name="parents",
    )

    def __str__(self):
        return self.title

app01/views.py

from django.shortcuts import render, HttpResponse
from django import forms
from app01 import models
from django.forms import formset_factory
# Create your views here.


class MultiPermissionForm(forms.Form):
    title = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    url = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    name = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    menu_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )
    pid_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["menu_id"].choices += models.Menu.objects.values_list("id", "title")
        self.fields["pid_id"].choices += models.Permission.objects.filter(
            pid__isnull=True).exclude(menu__isnull=True).values_list("id", "title")


class MultiUpdatePermissionForm(forms.Form):
    """多加一个id,这样方便于编辑的时候对相应的表单进行更新操作"""
    id = forms.IntegerField(
        widget=forms.HiddenInput(),  # 隐藏的输入框,无需给用户知道
    )
    title = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    url = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    name = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    menu_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )
    pid_id = forms.ChoiceField(
        choices=[(None, "-----")],
        widget=forms.Select(attrs={"class": "form-control"}),
        required=False,
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["menu_id"].choices += models.Menu.objects.values_list("id", "title")
        self.fields["pid_id"].choices += models.Permission.objects.filter(
            pid__isnull=True).exclude(menu__isnull=True).values_list("id", "title")


def multi_add(request):
    """
    批量添加
    :param request:
    :return:
    """
    # extra代表实例化了2个MultiPermissionForm
    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)
    # [form(字段, 错误), form(字段, 错误), form(字段, 错误)]
    # 如果表单数据都为空,那么不会做任何校验
    if formset.is_valid():
        # print(formset.cleaned_data)  # [{}, {}]
        flag = True
        # 将unique的错误添加到指定字段
        post_row_list = formset.cleaned_data  # 检查formset中有没有错误信息,将用户提交的数据获取到
        """
        formset.cleaned_data = [
                {'title': '123', 'url': '123', 'name': '123', 'menu_id': '1', 'pid_id': ''},
                {'title': '321', 'url': '321', 'name': '321', 'menu_id': '2', 'pid_id': ''}
            ]
        """
        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})
        # for row in formset.cleaned_data:
        #     # [ {}, {}, {}]
        #     # models.Permission.objects.create(**row)  # 这种方式不推荐,如果是unique错误此种方式捕捉不到
        #     try:
        #         obj = models.Permission(**row)
        #         obj.validate_unique()  # 检查当前对象在数据库是否存在唯一的异常
        #         obj.save()
        #     except Exception as e:
        #         pass

    return render(request, "multi_add.html", {"formset": formset})


def multi_edit(request):
    """
    批量编辑
    :param request:
    :return:
    """
    formset_class = formset_factory(MultiUpdatePermissionForm, extra=0)
    if request.method == "GET":
        # formset = formset_class(
        #     initial=[
        #         {"id": 1, "title": "x1", "url": "xxx"},
        #         {"id": 2, "title": "x2", "url": "ooo"}
        #     ]
        # )
        formset = formset_class(
            initial=models.Permission.objects.all().values("id", "name", "title", "url", "menu_id", "pid_id")
        )
        return render(request, "multi_edit.html", {"formset": formset})
    formset = formset_class(data=request.POST)
    if formset.is_valid():
        flag = True
        post_row_list = formset.cleaned_data
        for i in range(0, formset.total_form_count()):
            row = post_row_list[i]
            if not row:
                continue
            permission_id = row.pop("id")  # 拿到表单的id
            # models.Permission.objects.filter(id=permission_id).update(**row)  # 和上面的一样,unique错误无法捕捉
            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)
        if flag:
            return HttpResponse("提交成功")
        else:
            return render(request, "multi_edit.html", {"formset": formset})
    return render(request, "multi_edit.html", {"formset": formset})

templates/multi_add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>批量添加</h1>
<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>
    <p><input type="submit" value="提交"></p>
    <a href="{% url 'multi_edit' %}">批量编辑</a>
</form>
</body>
</html>

templates/multi_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>批量编辑</h1>
<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>
    <p><input type="submit" value="提交"></p>
    <a href="{% url 'multi_add' %}">批量添加</a>
</form>
</body>
</html>

 

 

 



这篇关于form组件之formset实现批量添加和编辑的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程