CRM项目之权限批量操作5

需先掌握的知识点

formset

Form组件或者ModelForm用于做一个表单的验证,一个表单即是一个表中的一行数据的操作。
formset组件是用于做多个表单验证的组件。
参考:formset批量操作多个表单

自动发现项目中的所有url

参考:自动发现项目中url

批量操作思路

  1. 自动发现的项目中所有带别名的权限,称之为a
  2. 数据库中已经存储了的权限,称之为b

以权限信息中的name作为对比,会有不同的三种情况
情况一:a的数量 > b的数量
出现场景是,项目开始阶段,数据库中还没有录入数据,自动发现的权限多,此时做数据库的权限批量增加。

情况二:a的数量 < b的数量
出现的场景是,项目中,我们在urls.py中注释掉了一些url(某些功能废弃的场景),数据库中还没有删除掉,此时需要做的是权限从数据库的批量删除。

情况三:a的数量 == b的数量
出现的场景是,项目中,一些url在urls.py中修改了内容,但是没有同步更新到数据库中,两处的信息不一致,此时做权限的批量更新到数据库。

批量操作页面展示

在此页面需展示三个部分:待新增内容、待删除内容、待更新内容
路由

url(r'^multi/permissions/$', menu.multi_permissions, name='multi_permissions'),

Form

class MultiAddPermissionForm(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)
        # 给Choice中动态添加数据库中的数据
        self.fields['menu_id'].choices += models.Menu.objects.all().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 MultiEditPermissionForm(forms.Form):
    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)
        # 给Choice中动态添加数据库中的数据
        self.fields['menu_id'].choices += models.Menu.objects.all().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_permissions(request):
    """
    批量操作权限
    :param request:
    :return:
    """
    # 获取项目中所有的url
    url_ordered_dict = get_all_url_dict()
    router_name_set = set(url_ordered_dict.keys())
    # 获取数据库中所有的url
    permissions = models.Permission.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id')
    permissions_dict = OrderedDict()
    for row in permissions:
        permissions_dict[row.get('name')] = row
    print(permissions_dict)
    permission_name_set = set(permissions_dict.keys())

    for name, value in permissions_dict.items():
        router_row_dict = url_ordered_dict.get(name)
        if not router_row_dict:
            # 数据库中有,自动发现的没有
            continue
        # 数据库和自动发现的都有,判断两者的url是否一致
        if value['url'] != router_row_dict['url']:
            print('数据库:{}({}) <==> 自动发现:{}({})'.format(value['url'], value['name'], router_row_dict['url'], router_row_dict['name']))
            value['url'] = "路由和数据库中不一致"


    # 应该添加、删除、修改的权限有哪些?
    # 添加 差集
    generate_name_list = router_name_set - permission_name_set
    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    generate_formset = generate_formset_class(
        initial=[row_dict for name, row_dict in url_ordered_dict.items() if name in generate_name_list]
    )


    # 删除 差集
    delete_name_list = permission_name_set - router_name_set

    delete_row_list = [row_dict for name, row_dict in permissions_dict.items() if name in delete_name_list]
    print(delete_row_list)
    # 更新 交集
    update_name_list = permission_name_set & router_name_set
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)
    update_formset = update_formset_class(
        initial=[row_dict for name, row_dict in permissions_dict.items() if name in update_name_list]
    )

    return render(request,
                  'rbac/multi_permissions.html',
                  {'generate_formset': generate_formset,
                   'delete_row_list': delete_row_list,
                   'update_formset': update_formset
                   }
                  )

模板multi_permissions.html

{% extends 'layout.html' %}
{% load rbac %}
{% block css %}
	<style>
		tr.active{
			border-left: 3px solid #fdc00f
		}
	</style>
{% endblock %}

{% block content %}
    <div class="luffy-container">
		<div class="row">
			<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待新建权限列表
					<a href="#" class="right btn btn-primary btx-xs"
					   style="margin: -3px; padding: 2px 8px;">
						<i class="fa fa-plus-circle" aria-hidden="true"></i>
						新建
					</a>
				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>菜单</th>
							<th>父权限</th>
						</tr>
					</thead>
					<tbody>
						{% for form in generate_formset %}
						<tr>
							<td>{{ forloop.counter }}</td>
							{% for field in form %}
								<td>
									{{ field }}
									<span style="color:red;">{{ field.errors.o }}</span>
								</td>
							{% endfor %}
						</tr>
						{% endfor %}
					</tbody>
				</table>
			</div>
		</div>
		<div class="row">
			<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待删除权限列表

				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>删除</th>
						</tr>
					</thead>
					<tbody>
						{% for row in delete_row_list %}
							<tr>
								<td>{{ forloop.counter }}</td>
								<td>{{ row.title }}</td>
								<td>{{ row.url }}</td>
								<td>{{ row.name }}</td>
								<td>
									<a style="color: #d9534f;" href="#">
											<i class="fa fa-trash-o"></i></a>
								</td>
							</tr>
						{% endfor %}
					</tbody>
				</table>
			</div>
		</div>
		<div class="row">
			<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待更新权限列表
					<a href="#" class="right btn btn-primary btx-xs"
					   style="margin: -3px; padding: 2px 8px;">
						<i class="fa fa-plus-circle" aria-hidden="true"></i>
						更新
					</a>
				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>菜单</th>
							<th>父权限</th>
						</tr>
					</thead>
					<tbody>
						{% for form in update_formset %}
						<tr>
							<td>{{ forloop.counter }}</td>
							{% for field in form %}
								{% if forloop.first %}
									{{ field }}
								{% else %}
									<td>
										{{ field }}
										<span style="color:red;">{{ field.errors.o }}</span>
									</td>
								{% endif %}
							{% endfor %}
						</tr>
						{% endfor %}
					</tbody>
				</table>
			</div>
		</div>
    </div>

{% endblock %}

效果:
在这里插入图片描述

批量增删改

就是界面上按钮的功能实现
对于增,点击待新建权限列表的新建按钮,就要将面板下所有的内容更新到数据库中,在面板外部用form包起来,一点击新建将所有内容提交。
对于删,就是待删除面板下的删除图标点击所触发的功能,将要删除的id传递到后端进行删除。
对于改,也就是更新功能,点击待更新面板上的更新按钮触发的功能,将面板中的所有表单更新到数据库中。

代码实现
路由

    # 批量操作权限
    url(r'^multi/permissions/$', menu.multi_permissions, name='multi_permissions'),
    url(r'^multi/permissions/del/(?P<pk>\d+)/$', menu.multi_permissions_del, name='multi_permissions_del'),

视图函数

def multi_permissions(request):
    """
    批量操作权限
    :param request:
    :return:
    """
    post_type = request.GET.get('type')  # 页面上新增和更新都是提交的post请求,增加参数来判断是新增还是更新

    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)

    generate_formset = None
    update_formset = None
    print(post_type, request.method)
    if request.method == 'POST' and post_type == 'generate':
        # 新增
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            has_error = False  # 用于判断是否所以数据都正确可存储到数据库
            post_row_list = formset.cleaned_data
            add_object_list = []  # 存储没有问题的数据对象
            for i in range(formset.total_form_count()):
                row_dict = post_row_list[i]
                try:
                    obj = models.Permission(**row_dict)
                    obj.validate_unique()
                    add_object_list.append(obj)
                except Exception as e:
                    formset.errors[i].update(e)
                    # 有错误信息的formset 传递到前端显示
                    generate_formset = formset
                    has_error = True
            if not has_error:
                # 所有的新增内容检测没有问题,才进行更新到数据库
                models.Permission.objects.bulk_create(add_object_list, batch_size=100)
        else:
            # 有错误信息的formset 传递到前端显示
            generate_formset = formset

    if request.method == 'POST' and post_type == 'update':
        # 更新
        formset = update_formset_class(data=request.POST)
        if formset.is_valid():
            post_row_list = formset.cleaned_data
            for i in range(formset.total_form_count()):
                row_dict = post_row_list[i]
                permission_id = row_dict.pop('id')
                try:
                    row_obj = models.Permission.objects.filter(pk=permission_id).first()
                    for key, value in row_dict.items():
                        setattr(row_obj, key, value)
                    row_obj.validate_unique()
                    row_obj.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    update_formset = formset
        else:
            # 带有错误信息的formset,没有通过验证,显示错误信息
            update_formset = formset

    # 获取项目中所有的url
    url_ordered_dict = get_all_url_dict()
    router_name_set = set(url_ordered_dict.keys())
    # 获取数据库中所有的url
    permissions = models.Permission.objects.all().values('id', 'title', 'name', 'url', 'menu_id', 'pid_id')
    permissions_dict = OrderedDict()
    for row in permissions:
        permissions_dict[row.get('name')] = row
    # print(permissions_dict)
    permission_name_set = set(permissions_dict.keys())

    for name, value in permissions_dict.items():
        router_row_dict = url_ordered_dict.get(name)
        if not router_row_dict:
            # 数据库中有,自动发现的没有
            continue
        # 数据库和自动发现的都有,判断两者的url是否一致
        if value['url'] != router_row_dict['url']:
            print('数据库:{}({}) <==> 自动发现:{}({})'.format(value['url'], value['name'], router_row_dict['url'], router_row_dict['name']))
            value['url'] = "路由和数据库中不一致"


    # 应该添加、删除、修改的权限有哪些?
    # 添加 差集
    if not generate_formset:
        generate_name_list = router_name_set - permission_name_set
        generate_formset = generate_formset_class(
            initial=[row_dict for name, row_dict in url_ordered_dict.items() if name in generate_name_list]
        )

    # 删除 差集
    delete_name_list = permission_name_set - router_name_set
    delete_row_list = [row_dict for name, row_dict in permissions_dict.items() if name in delete_name_list]
    
    # print(delete_row_list)
    # 更新 交集
    if not update_formset:
        update_name_list = permission_name_set & router_name_set

        update_formset = update_formset_class(
            initial=[row_dict for name, row_dict in permissions_dict.items() if name in update_name_list]
        )

    return render(request,
                  'rbac/multi_permissions.html',
                  {
                      'generate_formset': generate_formset,
                      'delete_row_list': delete_row_list,
                      'update_formset': update_formset
                  }
                  )


def multi_permissions_del(request, pk):
    """
    批量权限管理页面的权限删除
    :param request:
    :param pk:
    :return:
    """
    basic_url = memory_reverse(request, 'rbac:multi_permissions')

    if request.method == "GET":
        return render(request, 'rbac/delete.html', {'cancel_url': basic_url})

    models.Permission.objects.filter(id=pk).delete()
    return redirect(basic_url)

模板

{% extends 'layout.html' %}
{% load rbac %}

{% block content %}
    <div class="luffy-container">

		<div class="row">
			<form action="?type=generate" method="post">
				{% csrf_token %}
				{{ generate_formset.management_form }}
				<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待新建权限列表
					<button href="#" class="right btn btn-primary btx-xs"
					   style="margin: -3px; padding: 2px 8px;">
						<i class="fa fa-plus-circle" aria-hidden="true"></i>
						新建
					</button>
				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>菜单</th>
							<th>父权限</th>
						</tr>
					</thead>
					<tbody>
						{% for form in generate_formset %}
						<tr>
							<td>{{ forloop.counter }}</td>
							{% for field in form %}
								<td>
									{{ field }}
									<span style="color:red;">{{ field.errors.0 }}</span>
								</td>
							{% endfor %}
						</tr>
						{% endfor %}
					</tbody>
				</table>
			</div>
			</form>
		</div>
		<div class="row">
			<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待删除权限列表

				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>删除</th>
						</tr>
					</thead>
					<tbody>
						{% for row in delete_row_list %}
							<tr>
								<td>{{ forloop.counter }}</td>
								<td>{{ row.title }}</td>
								<td>{{ row.url }}</td>
								<td>{{ row.name }}</td>
								<td>
									<a style="color: #d9534f;" href="{% url 'rbac:multi_permissions_del' pk=row.id %}">
											<i class="fa fa-trash-o"></i></a>
								</td>
							</tr>
						{% endfor %}
					</tbody>
				</table>
			</div>
		</div>
		<div class="row">
			<form action="?type=update" method="post">
				{% csrf_token %}
				{{ update_formset.management_form }}
				<div class="panel panel-info">
				<!-- Default panel contents -->
				<div class="panel-heading">
					<i class="fa fa-th-list" aria-hidden="true"></i>待更新权限列表
					<button href="#" class="right btn btn-primary btx-xs"
					   style="margin: -3px; padding: 2px 8px;">
						<i class="fa fa-plus-circle" aria-hidden="true"></i>
						更新
					</button>
				</div>

				<!-- Table -->
				<table class="table">
					<thead>
						<tr>
							<th>序号</th>
							<th>名称</th>
							<th>URL</th>
                            <th>别名</th>
							<th>菜单</th>
							<th>父权限</th>
						</tr>
					</thead>
					<tbody>
						{% for form in update_formset %}
						<tr>
							<td>{{ forloop.counter }}</td>
							{% 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>
			</div>
			</form>
		</div>
    </div>

{% endblock %}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值