进行展示的时候, 肯定是通过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})
批量就做好了, 至于想让,那个权限属于谁。 看实际情况进行。 自行选择。
无法进行,程序的强制限制。 太麻烦
来源:https://www.cnblogs.com/chengege/p/10723314.html