python 全栈开发,Day110(django ModelForm,客户管理之 编辑权限(一))
昨日内容回顾
1. 简述权限管理的实现原理。
粒度控制到按钮级别的权限控制
- 用户登陆成功之后,将权限和菜单信息放入session
- 每次请求时,在中间件中做权限校验
- inclusion_tag实现的动态菜单 2. 表结构
有6张表,分别是:
菜单表,权限表,角色,用户表,用户角色关系表,角色权限关系表 3. 知识点
- 中间件白名单:配置文件、中间件return None
- 权限初始化:
- left join
- 特殊字典的构造
权限 = {
权限别名:{id:'',title:'',url,pid:''},
权限别名:{id:'',title:'',url,pid:''},
权限别名:{id:'',title:'',url,pid:''},
} 菜单 = {
菜单ID:{
title:'',
icon:'',
children:[
{id:'',.....}
]
}
}
- key为数字的字典,在序列化时会变成字符串(*)
- 配置文件 - 中间件进行权限校验
- 权限校验
- 导航路径
- pid,访问无法成为菜单的权限时,默认展开的父级权限ID - 动态生成菜单
- 通过inclusion_tag和两层for循环 + 中间件传来的pid - 粒度控制到按钮
- 基于filter并通过 别名 进行权限的判断;
一、django ModelForm
什么是ModelForm
Django中Model负责操作数据库,并且具有简单的数据库验证功能;Form用于用户请求的验证,具有强悍的数据库验证功能;ModelForm是将二者合二为一,即可用于数据库操作(部分),也可用于用户请求的验证(部分)!
其实Django Admin就是利用ModelForm的功能实现的。
Form组件和ModelForm的区别
ModelForm是Django Model.py和Form组件的结合体,可以简单/快速使用 Form验证和数据库操作功能,但不如Form组件灵活,如果在使用Django做web开发过程中验证的数据和数据库字段相关(可以对表进行增、删、改操,注意 Many to many字段,也可以级联操作第3张关系表;),建议优先使用ModelForm,用起来更方便些,但是在使用ModelForm的时候慎用fields='__all__',获取数据库所有字段势必造成性能损耗;
ModelForm应用场景
我们来假设这样一个场景,假如,我们有一个类需要保存org的一些信息如下面这些字段。这个类我们叫做ChangOrgModel
course_num = models.IntegerField(default=0, verbose_name=u'课程数')
students_num = models.IntegerField(default=0, verbose_name=u'学习人数')
address = models.CharField(max_length=200, verbose_name=u'地址')
如果我们使用form我们需要怎么做呢。我们大概需要这样做。
class OrgModelForm(forms.Form):
course_num = forms.IntegerField()
students_num = forms.IntegerField()
address = forms.CharField(max_length=200)
我们不难发现,我们的Form定义跟Model的定义基本没什么区别,应该加max_length的时候还是需要加,我们相当于是重写了一遍,其次,这里只有三个,并没有感觉,当有7、8甚至更多的时候,这样重复操作就很让人受不了了。所以这里我们可以使用ModelForm。
定义ModelForm类
from django import forms
from app01 import models class UserModelForm(forms.ModelForm):
class Meta:
model = models.User #关联的model类
fields = "__all__" #或('name','email','user_type') #验证哪些字段,"__all__"表示所有字段
exclude = None #排除的字段
labels = None #提示信息
help_texts = None #帮助提示信息
widgets = None #自定义插件
error_messages = None #自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
field_classes = None #自定义字段类(也阔以自定义字段)
localized_fields = () #本地化,根据settings中TIME_ZONE设置的不同时区显示时间
ModelForm验证执行的过程
Form所有的钩子ModelForm都有。
is_valid()-->self.errors-->full_clean()-->self._clean_fields() --> clean_字段名(自定义方法)
self._clean_form() --> clean(self)
self._post_clean() (整体错误) clean_字段名(自定义方法)
举例
新建一个项目untitled1,注意: django版本为1.11
修改models.py
from django.db import models class Depart(models.Model): # 部门
caption = models.CharField(verbose_name='部门',max_length=32) def __str__(self):
return self.caption
class Role(models.Model): # 角色
title = models.CharField(verbose_name='角色名',max_length=32) def __str__(self):
return self.title class User(models.Model): # 用户 name = models.CharField(verbose_name='姓名',max_length=32)
depart = models.ForeignKey(verbose_name='部门',to='Depart',on_delete=models.CASCADE) gender_choices = (
(1,'男'),
(2,'女'),
)
gender = models.IntegerField(verbose_name='性别',choices=gender_choices,default=1) roles = models.ManyToManyField(verbose_name='角色',to='Role')
执行2个命令,生成表
python manage.py makemigrations
python manage.py migrate
修改admin.py,注册表
from django.contrib import admin
from app01 import models
# Register your models here. admin.site.register(models.Depart)
admin.site.register(models.Role)
admin.site.register(models.User)
创建超级用户
python manage.py createsuperuser
登录admin后台,录入数据。这样做的目的是为了渲染页面时,不会出现空页面!
录入基本数据
新建部门
新建角色
修改urls.py,增加路由
from app01 import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/list/$', views.user_list),
]
修改views.py,增加视图
from django.shortcuts import render
from app01 import models
# Create your views here.
def user_list(request):
user_queryset = models.User.objects.all()
return render(request,'user_list.html',{'user_queryset':user_queryset})
在templates目录下,创建文件user_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<a href="/user/add/" class="btn btn-primary">添加</a>
<table class="table table-bordered">
<thead>
<tr>
<th>名称</th>
<th>性别</th>
<th>部门</th>
<th>角色</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for row in user_queryset %}
<tr>
<td>{{ row.name }}</td>
<td>{{ row.get_gender_display }}</td>
<td>{{ row.depart.caption }}</td>
<td>
{% for node in row.roles.all %}
<span>{{ node.title }}</span>
{% endfor %}
</td>
<td>
<a href="/user/edit/{{ row.id }}/">编辑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>
访问页面:http://127.0.0.1:8000/user/list/
默认是空的。需要写添加页面
添加页面,怎么写呢?写4个input框?假如有10个表呢?累成狗!
使用ModelForm,根据models.py定义的字段,自动生成input框!
添加功能
修改urls.py,增加路由
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/list/$', views.user_list),
url(r'^user/add/$', views.user_add),
]
修改views.py,增加添加页面,使用ModelForm
需要导入forms组件
from django import forms
完整代码如下:
from django.shortcuts import render,redirect
from app01 import models
from django import forms # Create your views here.
def user_list(request):
user_queryset = models.User.objects.all()
return render(request,'user_list.html',{'user_queryset':user_queryset}) class UserForm(forms.ModelForm): # 类名最好是表名+Form
class Meta:
model = models.User # user表
fields = '__all__' # 所有字段
# fields = ['name','depart']
widgets = {
# 定义name字段的输入框为text
'name':forms.TextInput(attrs={'class':'form-control'}),
# 定义depart字段的输入框为Select
'depart':forms.Select(attrs={'class':'form-control'}),
'gender':forms.Select(attrs={'class':'form-control'}),
# 定义roles字段的输入框为多选框
'roles':forms.SelectMultiple(attrs={'class':'form-control'}),
}
# 错误信息
error_messages = {
# name字段的错误信息
'name':{
# 英文的required转为中文提示
'required':'用户名不能为空'
}
} def user_add(request):
if request.method == "GET":
form = UserForm() # 实例化一个空的ModelForm对象
else:
form = UserForm(request.POST) # 接收POST请求数据
if form.is_valid(): # 进行验证
print('通过验证')
form.save() # 将验证通过的数据插入到数据库中
return redirect('/user/list/') # 重定向页面 return render(request,'user_add.html',{'form':form})
在templates目录下,创建文件user_add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>添加用户</h1>
<form method="post" class="form-horizontal" novalidate>
{% csrf_token %}
{#for循环form对象#}
{% for field in form %}
<div class="form-group">
{#显示字段名#}
<label class="col-sm-2 control-label">{{ field.label }} </label>
<div class="col-sm-10">
{#显示字段的输入框以及错误信息,0表示取第一个错误#}
{{ field }} {{ field.errors.0 }}
</div>
</div>
{% endfor %}
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
刷新页面,点击添加,效果如下:
直接提交空表单,会有错误提示
添加一个正常数据
添加成功后,页面会自动跳转
修改功能
修改urls.py,增加路由
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/list/$', views.user_list),
url(r'^user/add/$', views.user_add),
url(r'^user/edit/(?P<uid>\d+)/$', views.user_edit),
]
修改views.py,增加视图
from django.shortcuts import render,redirect
from app01 import models
from django import forms # Create your views here.
def user_list(request):
user_queryset = models.User.objects.all()
return render(request,'user_list.html',{'user_queryset':user_queryset}) class UserForm(forms.ModelForm): # 类名最好是表名+Form
class Meta:
model = models.User # user表
fields = '__all__' # 所有字段
# fields = ['name','depart']
widgets = {
# 定义name字段的输入框为text
'name':forms.TextInput(attrs={'class':'form-control'}),
# 定义depart字段的输入框为Select
'depart':forms.Select(attrs={'class':'form-control'}),
'gender':forms.Select(attrs={'class':'form-control'}),
# 定义roles字段的输入框为多选框
'roles':forms.SelectMultiple(attrs={'class':'form-control'}),
}
# 错误信息
error_messages = {
# name字段的错误信息
'name':{
# 英文的required转为中文提示
'required':'用户名不能为空'
}
} def user_add(request):
if request.method == "GET":
form = UserForm() # 实例化一个空的ModelForm对象
else:
form = UserForm(request.POST) # 接收POST请求数据
if form.is_valid(): # 进行验证
print('通过验证')
form.save() # 将验证通过的数据插入到数据库中
return redirect('/user/list/') # 重定向页面 return render(request,'user_add.html',{'form':form}) def user_edit(request,uid):
# 查询指定id的数据
obj = models.User.objects.filter(id=uid).first()
if request.method =='GET':
# 赋值instance可以使form表单是可以接受对象的数据
form = UserForm(instance=obj)
return render(request,'user_edit.html',{'form':form})
else:
# instance的参数,如果存在那么save()方法会更新这个实例,否则会创建一个新的实例
# 由于这里是更新,如果不指定instance。那么它会新增一条数据
# 我们这里不需要新增,必须要指定instance参数
form = UserForm(data=request.POST,instance=obj)
if form.is_valid():
form.save() # 更新一条数据
return redirect('/user/list/') # 重定向
else:
return render(request, 'user_edit.html', {'form': form})
在templates目录下,创建文件user_edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>编辑用户</h1>
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div>{{ field.label }}{{ field }} {{ field.errors.0 }}</div>
{% endfor %}
<input type="submit" value="提交">
</form>
</div> </body>
</html>
刷新页面,点击第一条数据后面的编辑,效果如下:
上面会自动渲染数据,那么问题来了,它是如何渲染页面的?
看views中的一段代码
if request.method =='GET':
# 赋值instance可以使form表单是可以接受对象的数据
form = UserForm(instance=obj)
return render(request,'user_edit.html',{'form':form})
这里的obj就是,表里面的一条数据,也就是一个对象。那么执行render时,会渲染这个变量。
看前端页面代码
<div>{{ field.label }}{{ field }} {{ field.errors.0 }}</div>
这里的field,就是字段对象。注意:这个对象是有值的,forms组件会渲染它!
修改一下数据
点击提交,它会自动跳转
数据就更改了!
删除功能
修改views.py
from django.shortcuts import render,redirect,HttpResponse
from app01 import models
from django import forms # Create your views here.
def user_list(request):
user_queryset = models.User.objects.all()
return render(request,'user_list.html',{'user_queryset':user_queryset}) class UserForm(forms.ModelForm): # 类名最好是表名+Form
class Meta:
model = models.User # user表
fields = '__all__' # 所有字段
# fields = ['name','depart']
widgets = {
# 定义name字段的输入框为text
'name':forms.TextInput(attrs={'class':'form-control'}),
# 定义depart字段的输入框为Select
'depart':forms.Select(attrs={'class':'form-control'}),
'gender':forms.Select(attrs={'class':'form-control'}),
# 定义roles字段的输入框为多选框
'roles':forms.SelectMultiple(attrs={'class':'form-control'}),
}
# 错误信息
error_messages = {
# name字段的错误信息
'name':{
# 英文的required转为中文提示
'required':'用户名不能为空'
}
} def user_add(request):
if request.method == "GET":
form = UserForm() # 实例化一个空的ModelForm对象
else:
form = UserForm(request.POST) # 接收POST请求数据
if form.is_valid(): # 进行验证
print('通过验证')
form.save() # 将验证通过的数据插入到数据库中
return redirect('/user/list/') # 重定向页面 return render(request,'user_add.html',{'form':form}) def user_edit(request,uid):
# 查询指定id的数据
obj = models.User.objects.filter(id=uid).first()
if request.method =='GET':
# 赋值instance可以使form表单是可以接受对象的数据
form = UserForm(instance=obj)
return render(request,'user_edit.html',{'form':form})
else:
# instance的参数,如果存在那么save()方法会更新这个实例,否则会创建一个新的实例
# 由于这里是更新,如果不指定instance。那么它会新增一条数据
# 我们这里不需要新增,必须要指定instance参数
form = UserForm(data=request.POST,instance=obj)
if form.is_valid():
form.save() # 更新一条数据
return redirect('/user/list/') # 重定向
else:
return render(request, 'user_edit.html', {'form': form}) def user_del(request,uid):
# 返回一个元组
obj = models.User.objects.filter(id=uid).delete()
if obj[0]:
return redirect('/user/list/')
else:
return HttpResponse('删除失败')
修改user_list.html,增加删除按钮
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<a href="/user/add/" class="btn btn-primary">添加</a>
<table class="table table-bordered">
<thead>
<tr>
<th>名称</th>
<th>性别</th>
<th>部门</th>
<th>角色</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for row in user_queryset %}
<tr>
<td>{{ row.name }}</td>
<td>{{ row.get_gender_display }}</td>
<td>{{ row.depart.caption }}</td>
<td>
{% for node in row.roles.all %}
<span>{{ node.title }}</span>
{% endfor %}
</td>
<td>
<a href="/user/edit/{{ row.id }}/">编辑</a>
<a href="/user/del/{{ row.id }}/">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>
刷新页面,点击删除
删除成功后,页面刷新
二、客户管理之 编辑权限(一)
由于时间关系.略...
效果图
http://127.0.0.1:8000/rbac/menu/list/
如果是二级菜单,有淡蓝色的背景
权限编辑
菜单编辑
完整代码如下:
链接:https://pan.baidu.com/s/1xYkyWFwmOZIFK4cqWWUizg 密码:zzs9
未完待续...
python 全栈开发,Day110(django ModelForm,客户管理之 编辑权限(一))的更多相关文章
- Python全栈开发:django网络框架(一)
Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...
- Python全栈开发:django网络框架(二)
Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行 ...
- python 全栈开发,Day111(客户管理之 编辑权限(二),Django表单集合Formset,ORM之limit_choices_to,构造家族结构)
昨日内容回顾 1. 权限系统的流程? 2. 权限的表有几个? 3. 技术点 中间件 session orm - 去重 - 去空 inclusion_tag filter 有序字典 settings配置 ...
- Python全栈开发【面向对象】
Python全栈开发[面向对象] 本节内容: 三大编程范式 面向对象设计与面向对象编程 类和对象 静态属性.类方法.静态方法 类组合 继承 多态 封装 三大编程范式 三大编程范式: 1.面向过程编程 ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- python全栈开发目录
python全栈开发目录 Linux系列 python基础 前端~HTML~CSS~JavaScript~JQuery~Vue web框架们~Django~Flask~Tornado 数据库们~MyS ...
- Python全栈开发相关课程
Python全栈开发 Python入门 Python安装 Pycharm安装.激活.使用 Python基础 Python语法 Python数据类型 Python进阶 面向对象 网络编程 并发编程 数据 ...
- Python 全栈开发【第0篇】:目录
Python 全栈开发[第0篇]:目录 第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...
- Python全栈开发【面向对象进阶】
Python全栈开发[面向对象进阶] 本节内容: isinstance(obj,cls)和issubclass(sub,super) 反射 __setattr__,__delattr__,__geta ...
随机推荐
- CM记录-CDH故障修复处理记录
CDH大数据集群修复记录 1)cm web打不开,查看监听7180端口产生了很多进程,于是kill进程:重启cloudera-cmf-server服务,几秒钟就挂了,查看cloudera-scm-se ...
- 跳表,Redis 为什么用跳表而不用平衡树?
https://juejin.im/post/57fa935b0e3dd90057c50fbc 在 Redis 中,list 有两种存储方式:双链表(LinkedList)和压缩双链表(ziplist ...
- Hdu 5072 Coprime(容斥+同色三角形)
原题链接 题意选出三个数,要求两两互质或是两两不互质.求有多少组这样的三个数. 分析 同色三角形n个点 每两个点连一条边(可以为红色或者黑色),求形成的三条边颜色相同的三角形的个数反面考虑这个问题,只 ...
- Java编程思想 学习笔记5
五.初始化与清理 1.用构造器确保初始化 在Java中,通过提供构造器,类的设计者可确保每个对象都会得到初始化.创建对象时,如果其类具有构造器,Java就会在用户有能力操作对象之前自动调用相应的构造 ...
- JAVA通过继承线性表来实现有序表
1,对于线性表而言,里面的元素是无序的,可以随意地将新元素增加到线性表中而不需要考虑该元素在线性表中的位置.但是,对于有序表而言,其中的元素是按照某种方式进行排序的,因此在有序表中插入元素时,需要按照 ...
- ettercap中间人攻击--参数介绍
攻击和嗅探 -M, --mitm ARP欺骗,参数 -M arp remote # 双向模式,同时欺骗通信双方,-M arp:remote. oneway #单向模式,只arp欺骗第一个 ...
- 法律AI数据及应用
本文简单列举了法律AI目前的应用,数据集,研究方向. 历史 1970年,Buchanan和Headrick发表文章"关于人工智能和法律推理的一些猜测",讨论了对法律研究和推理进行建 ...
- Linux - sort 排序
-t # 指定排序时所用的栏位分隔字符 -n # 依照数值的大小排序 -r # 以相反的顺序来排序 -f # 排序时,将小写字母视为大写字母 -d # 排序时,处理英文字母.数字及空格字符外,忽略其他 ...
- 第4月第20天 python re xls2lua
1. import re replace_values = ['one', 'two', 'three'] replace_keys = [str(i) for i in xrange(1, 4)] ...
- (原创)高仿360云盘android端的UI实现
前些日子几大互联网巨头展开了一轮网盘空间大战.一下子从G级别提高到了T级别.以后谁的空间没有1T估计都不好意思开口了~~~ 试用了一下360云盘的客户端,比较小清新(不是给360打广告~~~).刚好U ...