rbac 权限分配, 基于formset实现,批量编辑

已经完成了  批量添加的功能。 还想要一个批量修改的功能了。
随之而来的第一个问题就是,  我们的formset 并不是一条记录。而是 多条记录,甚至整个表的记录。
那么显而易见的问题就是,当前端页面把数据,返回给服务端的时候。  我怎么就知道,这条数据,是对应的数据库的那一条记录呢?
毕竟  不管是  title、 url、 name、 menu_id、 pid_id  都无法保证我去数据库中,找到与之相对应的这条记录。

所以我们就只能再加上一个字段,就是每一条数据的 主键 id 字段。
所以,我的form类,就得这么写了:

UpdateMultiPermissionForm

class UpdateMultiPermissionForm(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(  # ChoiceField 和 choices 就表示数据源
        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
    )

    # 因为 menu_id 和 pid_id ,应该是一个可以选择的下拉框形式, 所以重写了 __init__初始化函数。
    # 让fields对象中的这两个字段, 与数据库中查询出的结果,进行拼接
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["menu_id"].choices += models.Menu.objects.values_list("mid", "title")
        self.fields["pid_id"].choices += models.Permission.objects.filter(pid__isnull=True).exclude(
            menu__isnull=True).values_list("id", "title")
        # 过滤出 pid==Null的 可以做二级菜单的, exclude排除 menu==Null,不属于任何一个一级菜单的。所有的权限记录
id = forms.IntegerField(widget=forms.HiddenInput)这个HiddenInput 就是要在前端页面上,渲染成一个隐藏的 input 标签。(ps:如果在控制台更改了这个input标签的value值,你猜会怎么样?)

anyway! 再创建一个编辑用的,页面吧! multi_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<form method="post">
    {% csrf_token %}
    {{ formset.management_form }}
    <table border="1">
        <thead>
        <tr>
            <th>标题</th>
            <th>url</th>
            <th>Code</th>
            <th>Menu</th>
            <th>权限</th>
        </tr>
        </thead>
        <tbody>
        {% for form in formset %}
            <tr>
                {% for field in form %}
                    {% if forloop.first %}
                        {{ field }}
                    {% else %}
                        <td>{{ field }} <span>{{ field.errors.0 }}</span></td>
                    {% endif %}
                {% endfor %}
            </tr>
        {% endfor %}
        </tbody>
    </table>
    <input type="submit" value="提交">
</form>

</body>
</html>

multi_edit.html

还记得  field  对象是什么样子吗?

<input type="hidden" name="form-0-id" value="2" id="id_form-0-id">
<input type="text" name="form-0-title" value="这是一个标题" class="form-control" id="id_form-0-title">
<input type="text" name="form-0-url" value="/costomer/list/" class="form-control" id="id_form-0-url">
<input type="text" name="form-0-name" value="costomer_list" class="form-control" id="id_form-0-name">
<select name="form-0-menu_id" class="form-control" id="id_form-0-menu_id">
  <option value="">---------</option>

  <option value="1" selected>客户管理</option>

  <option value="2">菜单2</option>

</select>
<select name="form-0-pid_id" class="form-control" id="id_form-0-pid_id">
  <option value="" selected>---------</option>

  <option value="2">这是一个标题</option>

  <option value="3">a1</option>

</select>

对 这就是 field 对象, 里面保存的东西!  可以看到,一共有 6 个标签。
第一个是一个需要隐藏起来的  input 标签。 因为这个是 id  不能让用户,更改。 更改了这个。 可就没法确定这条数据是对应的数据库那条记录了。
然后前端页面渲染的时候,也不能直接就,还像添加页面那样处理。   因为第一个标签,是需要隐藏起来的, 不能给他添加一个 <td></td> 标签。否则页面就乱了
所以加上一个判断  forloop.first  如果是第一次循环的话, 就只放一个 input 标签在这就好, 并且因为是隐藏的,不会扰乱页面。

OK 到这里。 渲染工作。 就做得差不多了! 然后就是 要怎么更新数据了!

def multi_edit(request):
    formset_class = formset_factory(UpdateMultiPermissionForm, extra=0)
    if request.method == "POST":
        formset = formset_class(data=request.POST)
        if formset.is_valid():
            post_row_date = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row = post_row_date[i]
                if not row:
                    continue
                permission_id = row.pop("id")
                models.Permission.objects.filter(pk=permission_id).update(**row)

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

    formset = formset_class(initial=models.Permission.objects.all()
                            .values("id", "title", "url", "name", "menu_id", "pid_id"))
    return render(request, "multi_edit.html", {"formset": formset})

def multi_edit(request):

这样就可以进行保存了。   然后问题就又 回来了!!   还是 唯一性 的问题:

def multi_edit(request):
    formset_class = formset_factory(UpdateMultiPermissionForm, extra=0)
    if request.method == "POST":
        formset = formset_class(data=request.POST)
        if formset.is_valid():
            post_row_date = formset.cleaned_data
            for i in range(0, formset.total_form_count()):
                row = post_row_date[i]
                if not row:
                    continue
                permission_id = row.pop("id")
                try:
                    permission_obj = models.Permission.objects.filter(pk=permission_id).first()  # 取出数据库中与当前permission_id相对应的数据对象
           #  然后 对应的 赋值。 在没有 seve() 之前, 是不会对数据库 有任何更改的。 说白了permission_obj现在只是内存中的一个model对象。
                    permission_obj.title = row.get("title")
                    permission_obj.name = row.get("name")
                    permission_obj.url = row.get("url")
                    permission_obj.menu_id = row.get("menu_id")
                    permission_obj.pid_id = row.get("pid_id")
                    permission_obj.validate_unique()  # 全部赋值完成之后,检测唯一性。  存在就抛出已存在的异常。
                    permission_obj.save()  # 如果没有抛出异常, 就进行保存的操作。
                except Exception as e:
                    pass
        return render(request, "multi_edit.html", {"formset": formset})

    formset = formset_class(initial=models.Permission.objects.all()
                            .values("id", "title", "url", "name", "menu_id", "pid_id"))
    return render(request, "multi_edit.html", {"formset": formset})

def multi_edit(request):

emmmmm  这样搞虽然麻烦一点,但是还是能完成任务的。  有没有简单一点的方法呢?
答案是一定有的:  这里用到了 类中  反射思想。   如果忘了,去看看笔记把:
完整版代码:

def multi_edit(request):
    formset_class = formset_factory(UpdateMultiPermissionForm, extra=0)
    if request.method == "POST":
        formset = formset_class(data=request.POST)
        if formset.is_valid():
            post_row_date = formset.cleaned_data
            flag = True
            for i in range(0, formset.total_form_count()):
                row = post_row_date[i]
                if not row:
                    continue
                permission_id = row.pop("id")
                try:
                    permission_obj = models.Permission.objects.filter(pk=permission_id).first()
                    for key, value in row.items():
                        setattr(permission_obj, key, value)
                    permission_obj.validate_unique()
                    permission_obj.save()
                except Exception as e:
                    formset.errors[i].update(e)
                    flag = False
            if flag:
                return HttpResponse("更新成功")
            # else:
            #     return render(request, "multi_edit.html", {"formset": formset})
        return render(request, "multi_edit.html", {"formset": formset})

    formset = formset_class(initial=models.Permission.objects.all()
                            .values("id", "title", "url", "name", "menu_id", "pid_id"))
    return render(request, "multi_edit.html", {"formset": formset})

def multi_edit(request): 完整版

这里要提一句: 前端中 每一行 就是一个form 。 进行保存的时候并没有说,多个form中,有一个出错的,其他的也不进行保存。
而是 出错的这条form  不会进行保存。  其他的没有出错的, 并不会受到影响。
还有就是  类的 反射。 是一个很重要的, 知识点,很重要的一个思想。  多多复习!

最后提一下 formset_class = formset_factory(UpdateMultiPermissionForm, extra=0)
这个formset_factory 默认会渲染一个form对象。 所以用的时候  extra 改成0. 就行了!

原文地址:https://www.cnblogs.com/chengege/p/10719062.html

时间: 2024-08-30 12:27:57

rbac 权限分配, 基于formset实现,批量编辑的相关文章

RBAC权限分配

RABC:基于角色的权限访问控制(Role-Based Access Control) 一般在登录系统认证通过后,会先确定的该用户的操作权限,判断用户的后续操作是否合法! RABC至少需要三张表:用户表--角色表--权限表(多对多的关系比较合理) 用户表:用来存储用户名和密码,进行登录校验,可以重写User表,使用django内置的auth认证系统,也可自定义: 角色表:对用户角色进行分配, 权限表:存储所有需要进行权限分配的url请求路径 RBAC权限分配操作过程: 用户登录,通过用户表校验用

vue基于d2-admin的RBAC权限管理解决方案

前两篇关于vue权限路由文章的填坑,说了一堆理论,是时候操作一波了. vue权限路由实现方式总结 vue权限路由实现方式总结二 选择d2-admin是因为element-ui的相关开源项目里,d2-admin的结构和代码是让我感到最舒服的,而且基于d2-admin实现RBAC权限管理也很方便,对d2-admin没有大的侵入性的改动. 预览地址 Github 相关概念 不了解RBAC,可以看这里企业管理系统前后端分离架构设计 系列一 权限模型篇 实现了RBAC模型权限控制 菜单与路由独立管理,完全

基于RBAC权限管理

一般web系统操作人员多时都会需求权限管理,一来限制操作范围,二来限制数据公开度. 现在最流行的一个模式为 RBAC (Role-Based Access Control) 基于角色的访问控制.设定权限范围定义到角色中,然后再分配到每个用户. 这里仅以一般后台管理系统为例,叙说数据结构: 需求: 菜单需要针对不同部门使用不同的菜单结构. 权限项能精确到页面中某个内容或局部功能. 基本要求:没有权限的菜单,页面中内容或链接禁止显示. 表结构 CREATE TABLE `power_item` (

基于RBAC权限管理模型学习

在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限.这就极大地简化了权限的管理. 在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色.角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收. 角色与角色的关系可以建立起来以囊括更广泛的客观情况. BAC支持三个著名的安全原则:最小权限原则,责任分离原则和数据抽象原则. (1)最小权限原则之所以被RBAC所支持,是因

ASP.NET 系列:RBAC权限设计

权限系统的组成通常包括RBAC模型.权限验证.权限管理以及界面访问控制.现有的一些权限系统分析通常存在以下问题: (1)没有权限的设计思路 认为所有系统都可以使用一套基于Table设计的权限系统.事实上设计权限系统的重点是判断角色的稳定性和找出最小授权需求.角色的稳定性决定了系统是通过角色判断权限还是需要引入RBAC方式,最小授权需求防止我们过度设计导致超出授权需求的权限粒度. (2)没有独立的RBAC模型的概念 直接使用实体类表示RBAC模型,导致本身本应该只有几行代码且可以在项目级别复用的R

转:RBAC权限控制

名词解释: RBAC:Role-Based Access Control,基于角色的访问控制 关键词: RBAC,Java Shiro,Spring Security, 一. RBAC 要解决的常见问题 问题一:对某一个用户只授予一些特殊的权限 描述:既不希望扩大某一个角色的权限,也不希望因此创建出很多零碎的.只为一个用户而存在的角色. 问题二:性能问题 描述:B/S 下,菜单.页面.页面元素.dataset的列,这些层层权限判断过于复杂,容易造成系统访问非常缓慢. 问题三:如何减少 HardC

RBAC权限控制

名词解释: RBAC:Role-Based Access Control,基于角色的访问控制 关键词: RBAC,Java Shiro,Spring Security, 一. RBAC 要解决的常见问题 问题一: 对某一个用户只授予一些特殊的权限 描述:既不希望扩大某一个角色的权限,也不希望因此创建出很多零碎的.只为一个用户而存在的角色. 问题二: 性能问题 描述:B/S 下,菜单.页面.页面元素.dataset的列,这些层层权限判断过于复杂,容易造成系统访问非常缓慢. 问题三: 如何减少 Ha

RBAC权限管理

RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限. 这样,就构造成“用户-角色-权限”的授权模型.在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系.(如下图) 角色是什么?可以理解为一定数量的权限的集合,权限的载体.例如:一个论坛系统,“超级管理员”.“版主”都是角色.版主可管理版内的帖子.可管理版内的用户等,这些是权限.要给某个用户授予这些权限,不需要直接

RBAC权限管理系统

权限控制应该是分为3类: 菜单级别 页面元素级别 数据级别 RBAC介绍 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用户-角色-权限"的授权模型.在这种模型中,用户与角色之间,角色与权限之间,一般是多对多的关系.(如下图) 角色是什么?可以理解为一定数量的权限的集合,权限的载体.例如:一个OA系统,"管理员"."