已经完成了  批量添加的功能。 还想要一个批量修改的功能了。
随之而来的第一个问题就是,  我们的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="">
<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. 就行了!

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

  1. RBAC权限分配

    RABC:基于角色的权限访问控制(Role-Based Access Control) 一般在登录系统认证通过后,会先确定的该用户的操作权限,判断用户的后续操作是否合法! RABC至少需要三张表:用户 ...

  2. rbac 权限分配, 基于formset实现,批量增加

    这里需要两个知识点: - formset - 自动发现项目中的URL1. 什么是formset: Django中 form组件 或 ModelForm组件,用于做一个表单的验证. 接收前端form表单 ...

  3. 权限组件(11):基于formset实现批量增加

    效果图: 增加页面: 编辑页面: 因为后面要对权限进行批量操作,所以先用这个示例演示下如何实现批量操作 数据库 from django.db import models class Menu(mode ...

  4. PHP RBAC权限管理 基于角色的访问控制演示

    RBAC rbac:Role Based Access Controll,基于角色的访问控制. 今天理一理RBAC,话不多说,直接切入主题 功能需求: 权限管理(无限极) 角色管理(可以分配权限) 管 ...

  5. JWT与RBAC权限模型

    JWT JWT是什么? Json web token (JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC7519),该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  6. rbac集成 权限分配。之角色管理

    权限分配功能拆分: a. 角色管理 b. 用户管理 c. 菜单和权限的管理 d. 批量的权限操作 e. 分配权限 先实现 角色管理: 无非也就是,增删改查: 定义路由, 编写视图. 1.查看角色页面: ...

  7. 权限管理系统(五):RBAC新解,基于资源的权限管理

    本文讨论以角色概念进行的权限管理策略及主要以基于角色的机制进行权限管理是远远不够的.同时我将讨论一种我认为更好的权限管理方式. 1.什么是角色 当说到程序的权限管理时,人们往往想到角色这一概念.角色是 ...

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

    前两篇关于vue权限路由文章的填坑,说了一堆理论,是时候操作一波了. vue权限路由实现方式总结 vue权限路由实现方式总结二 选择d2-admin是因为element-ui的相关开源项目里,d2-a ...

  9. rbac结合ssm实现权限分配和管理

    RBAC(Role-Based Access Control )基于角色的访问控制. RBAC 认为权限的过程可以抽象概括为: 判断[Who 是否可以对 What 进行 How 的访问操作(Opera ...

随机推荐

  1. 【365】拉格朗日乘子法与KKT条件说明

    参考:知乎回答 - 通过山头形象描述 参考:马同学 - 如何理解拉格朗日乘子法? 参考: 马同学 - 如何理解拉格朗日乘子法和KKT条件? 参考:拉格朗日乘数 - Wikipedia 自己总结的规律 ...

  2. jQuery添加添加时间与时间戳相互转换组件

    时间与时间戳的格式相互转换(转换主要兼容ie8,ie8不支持new Date()) (function($) { $.extend({ myTime: { CurTime: function () { ...

  3. MVC缺点总结

    MVC的缺点: 1.完全理解MVC比较复杂. 由于MVC模式提出的时间不长,加上同学们的实践经验不足,所以完全理解并掌握MVC不是一个很容易的过程. 2.调试困难. 因为模型和视图要严格的分离,这样也 ...

  4. ArcGIS特殊标注效果的简单实现

    1. 普通纯色背景:例如望仙亭,水垄沟: 方法:   2. 背景+边框 例如进入点 方法:    

  5. ROS:ROS操作类MK.cs

    class MK { Stream connection; TcpClient con; public MK(string ip,int port) { con = new TcpClient(); ...

  6. C# windows服务:如何检测指定的Windows服务是否启动

    public void CheckServerState(string ServiceName) { ServiceController[] service = ServiceController.G ...

  7. vs2017中char* str = "1234asd56";会报错,——const char*类型的值不能用于初始化char*类型的实体

    原因: "1234asd56"是常量 ,正确的写法本身就是:const char* str = "1234asd56"; 之所以之前的vs版本可以写成char* ...

  8. python基础学习Day17 面向对象的三大特性之继承、类与对象名称空间小试

    一.课前回顾 类:具有相同属性和方法的一类事物 实例化:类名() 过程: 开辟了一块内存空间 执行init方法 封装属性 自动的把self返回给实例化对象的地方 对象:实例 一个实实在在存在的实体 组 ...

  9. jekins的一些配置

    GotPC_Excel_Branches丢弃旧的构建 svn http://devsvn.uuzuonline.com/GOT_PC_PRIVATE/config/trunk构建Execute she ...

  10. apache启动报错(98)Address already in use: make_sock: could not bind to address [::]:80

    说明80端口被用 终端:  ps -ef|grep httpd察看占用的进程或者用netstat -lnp|grep 80 找到后kill掉,如果都不行那么再试试以下方法(试过可以) 终端输入: fi ...