进行展示的时候, 肯定是通过formset 来完成这项工作。
1. 获取项目中所有的,想要的权限。 比如保存在一个集合中。 set1
2. 获取数据库中,已经录入了的所有权限。 保存在另一个集合中。 set2

下面 就出现了三种情况:(这里还是需要通过name字段,来进行 判断。 两个集合)
  情况一: set1 比 set2  多。  说明就要把 多出来的 添加到数据库。 批量添加
  情况二: set1 比 set2 少。说明中途可能弃用了一部分url。 数据库就要删除这部分。  批量删除。
  情况三: set1 和 set2 一样多。 但是可能url 改变了。 所以就需要将 set1 中查出的 与 set2 中中查出的, name一样。 url 不一样的,进行批量更新。

OK  大概也就这三种情况:  一个一个的实现:
1.  我已经从项目中获取了,所有的url。 还需要把数据库中,保存着的 permission 的所有信息全部拿到。

    permissions = models.Permission.objects.all().values("pk", "title", "name", "url", "menu_id", "pid_id")
    permission_dict = OrderedDict()
    permission_name_set = set()
    for row in permissions:
        permission_dict[row.get("name")] = row
        permission_name_set.add(row.get("name"))

在这里也是使用的  OerderdDict  有序字典。
然后放入到了一个  集合当中。 这个集合只放了   每一条记录中的  name 字段的。 信息。
看看什么样:

permission_name_set
{'role_edit', 'customer_edit', 'payment_add', 'payment_list', 'payment_del', 'second_menu_del', 'role_list', 'menu_list',
'menu_del', 'customer_del', 'user_list', 'customer_import', 'user_add', 'user_del', 'permission_edit', 'permission_add',
'customer_tpl', 'reset_pwd', 'second_menu_add', 'menu_add', 'customer_list', 'menu_edit', 'user_edit', 'payment_edit',
'second_menu_edit', 'permission_del', 'customer_add', 'role_add', 'role_del'}

自动获取, 得到的也是一个字典。  也需要将每一个 字典的key 保存到一个集合当中:

all_url_dict = get_all_url_dict()
router_name_set = set(all_url_dict.keys())
router_name_set
{'role_edit', 'customer_edit', 'payment_add', 'multi_permissions', 'payment_list', 'payment_del', 'second_menu_del', 'role_list',
'menu_list', 'menu_del', 'customer_del', 'user_list', 'customer_import', 'user_add', 'user_del', 'permission_edit',
'permission_add', 'customer_tpl', 'reset_pwd', 'second_menu_add', 'menu_add', 'customer_list', 'menu_edit', 'user_edit',
'payment_edit', 'second_menu_edit', 'permission_del', 'customer_add', 'role_add', 'role_del'}

两个集合有了: 该做差集 并集 操作了!
情况一。 批量添加操作: 自动获取中有的, 数据库没有的, 需要进行添加到数据库:

    # 3.1 计算出应该添加的name 并生成 formset (自动发现有的,数据库没有的。所以要循环的是 自动发现查询出的字典)
    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 all_url_dict.items() if name in generate_name_list])

这里有关 formset的操作,不再说: 前面的博客中有提到,(忘了就去复习)
这段代码做的事情就是  将每一个 row_dict 中我保存的  name 和 url 交给了  MultiAddPermissionForm 类里面定义的 name 和 url。
title  肯定是空的。 因为这需要, 用户自己起名字吗嘛!

情况二: 批量删除操作:自动获取中没有的, 数据库有的, 需要从数据库删除掉:

(数据库有的,自动发现 没有的。所以要循环的是 数据库查询出的字典) 
delete_name_list = permission_name_set - router_name_set # 删除列表 # 页面展示时 不需要删除的formset 只提供一个删除按钮就好 delete_row_list = [row_dict for name, row_dict in permission_dict.items() if name in delete_name_list]

删除操作, 就不涉及任何修改了。 直接使用一个列表, 前端循环列表然后,进行渲染就行了!

情况三: 批量更新操作: 自动获取中有的, 数据库有的。

    for name, value in permission_dict.items():
        router_row = all_url_dict.get(name)  # 从all_url_dict取出key为 name 的值
        if not router_row:  # 如果没有找到,直接跳过。
            continue
        if value.get("url") != router_row.get("url"):  # 找到的情况下, 比对 两个的 url 是否一直
            value["url"] = "路由和数据库中不一致,请检查。并填写正确的  url!!"

    # 3.3 计算出应该更新的name (数据库有的,自动发现有的。所以要循环的是 数据库查询出的字典)
    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 permission_dict.items() if name in update_name_list])

这里先一步对两个 字典中的数据进行了比较。 因为有可能会有  name 是一样的,但是 url 不一样的情况。
那就需要  对 用户有个提示。 所以做了个循环的判断。 发现url 不相等的情况时, 就将这个url 给修改成一个 提示字符串。然后让用户自己去检查,要使用
那个url  然后填写正确的 url  进行保存。

 最后就是, 前端页面的渲染,然后让用户进行操作完成之后的保存了!

不论是 添加还是 更新, 都需要一个 form 标签。来进行数据的传递。 action="" 表示。默认使用当前页面的 url 进行数据发送。
为了分清,我这次提交的数据, 是添加的, 还是更新的。 我改变了一下action。

<form method="post" action="?type=generate">
    ......
</form>

<form method="post" action="?type=update">
    ......
</form>
post_type = request.GET.get("type") 判断GET 中取到的是generate 或者 update  来判断这次的数据,是用于添加或者更新
def multi_permissions(request):
    '''
    批量操作权限
    :param request:
    :return:
    '''
    post_type = request.GET.get("type")
    generate_formset = None
    update_formset = None
    update_formset_class = formset_factory(MultiEditPermissionForm, extra=0)
    generate_formset_class = formset_factory(MultiAddPermissionForm, extra=0)
    if request.method == "POST" and post_type == "generate":  # 批量添加
        formset = generate_formset_class(data=request.POST)
        if formset.is_valid():
            has_error = False  #  判定是否有发生错误
            object_list = []  # 添加时 将每一个model对象 添加到  object_list  列表中
            post_row_list = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row_dict = post_row_list[i]  # 根据索引拿到 每一行用户上传的数据(得到的是一个字典)
                if not row_dict:
                    continue
                try:
                    new_object = models.Permission(**row_dict)  # 将字典交给Permission模型。得到model对象
                    new_object.validate_unique()  # 判断与数据库中  有限制unique的字段,是否重复。  如果有抛出异常
                    object_list.append(new_object)  # 无异常的 添加到列表中
                except Exception as e:
                    formset.errors[i].update(e)  #  捕获错误, 并将错误信息,添加到当前form对象的error字典中。
                    generate_formset = formset  # 将接收用户数据之后的 formset 重新赋值给generate_formset (前端才能显示错误信息)
                    has_error = True  # 发生过错误,更改状态
            if not has_error:  # 如果发生了错误,就不进行更新保存的操作
                models.Permission.objects.bulk_create(object_list, batch_size=100)  # 批量添加
        else:
            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(0, formset.total_form_count()): row_dict = post_row_list[i] permission_id = row_dict.pop("id") try: row_object = models.Permission.objects.filter(pk=permission_id).first() for k, v in row_dict.items(): setattr(row_object, k, v) # model对象也是一个 类 实例化来的。 所以使用反射 进行赋值操作 row_object.validate_unique() row_object.save() # 更新只能是,一条一条的 逐条更新。 无法批量 except Exception as e: formset.errors[i].update(e) update_formset = formset else: update_formset = formset # 1.获取项目中,所有的URL all_url_dict = get_all_url_dict() router_name_set = set(all_url_dict.keys()) # 2. 获取数据库中所有的url permissions = models.Permission.objects.all().values("id", "title", "name", "url", "menu_id", "pid_id") permission_dict = OrderedDict() permission_name_set = set() for row in permissions: permission_dict[row.get("name")] = row permission_name_set.add(row.get("name"))
# permission_name_set = set(permission_dict.keys()) # 以下循环主要是为了,进行更新操作的时候。有可能自动发现和数据库中 name 一样而url不一样时。强制更改一下 # 让用户去自己去检查一下。 到底要使用 那个url。 需要用户自己手动填写 for name, value in permission_dict.items(): router_row = all_url_dict.get(name) if not router_row: continue if value.get("url") != router_row.get("url"): value["url"] = "路由和数据库中不一致,请检查。并填写正确的 url!!" # 3. 应该要 添加,删除,修改的权限有哪些 # 3.1 计算出应该添加的name 并生成 formset (自动发现有的,数据库没有的。所以要循环的是 自动发现查询出的字典) 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 all_url_dict.items() if name in generate_name_list]) # 3.2 计算出,应该删除的name,(数据库有的,自动发现 没有的。所以要循环的是 数据库查询出的字典) delete_name_list = permission_name_set - router_name_set # 删除列表 # 页面展示时 不需要删除的formset 只提供一个删除按钮就好 delete_row_list = [row_dict for name, row_dict in permission_dict.items() if name in delete_name_list] # 3.3 计算出应该更新的name (数据库有的,自动发现有的。所以要循环的是 数据库查询出的字典) 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 permission_dict.items() if name in update_name_list]) return render(request, "rbac/multi_permission.html", {"generate_formset": generate_formset, "delete_row_list": delete_row_list, "update_formset": update_formset}, ) def multi_permissions_del(request, pk): ''' 删除操作, 需要给与用户提示。 :param reuqest: :param pk: 要删除的权限id :return: ''' origin_url = memory_reverse(request, "rbac:multi_permissions") permission_queryset = models.Permission.objects.filter(pk=pk) if not permission_queryset: return HttpResponse("菜单不存在") if request.method == "POST": permission_queryset.delete() return redirect(origin_url) return render(request, "rbac/delete.html", {"cancel": origin_url})

批量就做好了, 至于想让,那个权限属于谁。 看实际情况进行。 自行选择。
无法进行,程序的强制限制。 太麻烦

 

posted on 2019-04-17 14:25  rookiehbboy  阅读(562)  评论(0编辑  收藏  举报