zoukankan      html  css  js  c++  java
  • 权限组件(11):基于formset实现批量增加

    效果图:

    增加页面:

    编辑页面:

     

    因为后面要对权限进行批量操作,所以先用这个示例演示下如何实现批量操作

    数据库

     

    from django.db import models
    
    
    class Menu(models.Model):
        """
        菜单表
        """
        title = models.CharField(verbose_name='菜单名称', max_length=32)
        icon = models.CharField(verbose_name='图标', max_length=32)
    
        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(verbose_name='所属菜单', to='Menu', null=True, blank=True,
                                 help_text='null表示不是菜单;非null表示是二级菜单', on_delete=models.CASCADE)
    
        pid = models.ForeignKey(verbose_name='关联的权限', to='Permission', null=True, blank=True, related_name='parents',
                                help_text='对于非菜单权限需要选择一个可以成为菜单的权限,用于做默认展开和选中菜单',
                                on_delete=models.CASCADE)
    
        def __str__(self):
            return self.title

     

     

    一、配置路由

    from django.urls import path
    from formset import views
    
    urlpatterns = [
        path('multi/add', views.multi_add),
        path('multi/edit', views.multi_edit),
    ]

    二、forms表单验证

    from django import forms
    
    from formset import models
    
    
    class MultiPermissionForm(forms.Form):
        title = forms.CharField()
        url = forms.CharField()
        name = forms.CharField()
        menu_id = forms.ChoiceField(
            choices=[(None, '----------')],
            required=False
        )
        pid_id = forms.ChoiceField(
            choices=[(None, '----------')],
            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 = forms.IntegerField(
            widget=forms.HiddenInput()
        )
        title = forms.CharField()
        url = forms.CharField()
        name = forms.CharField()
        menu_id = forms.ChoiceField(
            choices=[(None, '----------')],
            required=False
        )
        pid_id = forms.ChoiceField(
            choices=[(None, '----------')],
            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')

    三、视图函数

    from django.forms import formset_factory
    from django.shortcuts import render, HttpResponse
    
    from formset import models
    from formset.forms.formset import MultiPermissionForm, MultiUpdatePermissionForm
    
    
    def multi_add(request):
        """
        批量增加
        :param request:
        :return:
        """
    
        formset_class = formset_factory(MultiPermissionForm, extra=5)  # 在内部生成五个form表单
    
        if request.method == 'GET':
            formset = formset_class()
            return render(request, 'multi_add.html', {'formset': formset})
    
        formset = formset_class(data=request.POST)  # 储存的所有信息,包括html标签
        if formset.is_valid():
            no_repeat_field = True
    
            # 要把cleaned_data放到for循环上面,因为在下面一旦cleaned_data检测到错误信息就会报错。里面储存了一个个form[{},{},{}......]
            form_list = formset.cleaned_data  # 检查formset中有没有错误信息,没有则将用户提交的数据取到。有错误信息就报错
            for num in range(0, formset.total_form_count()):
                form = form_list[num]  # 一个具体的form
                if not form:
                    continue
                try:
                    # 下面的方式和model.Permission.object.create(**row)效果一样,这里用这种方式是为了捕获唯一性错误
                    permission_obj = models.Permission(**form)
                    permission_obj.validate_unique()  # 检查当前对象在数据库是否存在唯一的
                    permission_obj.save()
                except Exception as e:
                    formset.errors[num].update(e)  # 把错误信息放到对应的form里面
                    no_repeat_field = False
    
            if no_repeat_field:
                return HttpResponse('提交成功')
            else:
                return render(request, 'multi_add.html', {'formset': formset})
        return render(request, 'multi_add.html', {'formset': formset})
    
    
    def multi_edit(request):
        formset_class = formset_factory(MultiUpdatePermissionForm, extra=0)  # 默认等于1,如果不想让它多增加一个,就把默认改成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():
            no_repeat_field = True
            form_list = formset.cleaned_data
            for num in range(0, formset.total_form_count()):
                form = form_list[num]
                if not form:
                    continue
                permission_id = form.pop('id')
                try:
                    permission_obj = models.Permission.objects.filter(id=permission_id).first()
                    for key, value in form.items():
                        setattr(permission_obj, key, value)  # 更新数据库的字段
                    permission_obj.validate_unique()
                    permission_obj.save()
                except Exception as e:
                    formset.errors[num].update(e)
                    no_repeat_field = False
            if no_repeat_field:
                return HttpResponse("提交成功")
            else:
                return render(request, 'multi_edit.html', {'formset': formset})
        return render(request, 'multi_edit.html', {'formset': formset})

     

    四、模板渲染

    multi_add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
    </head>
    <body>
    
    <div class="container" style="margin-top: 100px">
        <div class="row">
            <form action="" method="post" novalidate>
                {% csrf_token %}
                {{ formset.management_form }}
                <table class="table table-hover table-stripped" 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>
                <hr/>
                <input type="submit" value="提交" class="btn btn-primary">
            </form>
        </div>
    </div>
    
    
    </body>
    </html>

    multi_edit.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
    </head>
    <body>
    
    <div class="container" style="margin-top: 100px">
        <div class="row">
            <form action="" method="post" novalidate>
                {% csrf_token %}
                {{ formset.management_form }}
                <table class="table table-hover table-stripped" 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>
                <hr/>
                <input type="submit" value="提交" class="btn btn-primary">
            </form>
        </div>
    </div>
    
    
    </body>
    </html>

    edit和add的区别是edit多了个id并把id隐藏起来了

  • 相关阅读:
    java----使用socket模拟简单的http请求服务器,响应简单的文件请求操作
    Java实现的断点续传功能
    C 语言——分支和跳转
    C 语言——嵌套循环例子
    C 语言——循环
    C 语言——运算符、表达式和语句
    C 语言——字符串和格式化输入/输出
    C 语言——基础概论
    C 语言——开篇
    IDEA的安装教程
  • 原文地址:https://www.cnblogs.com/lshedward/p/10512069.html
Copyright © 2011-2022 走看看