Python系统学习-24

今日内容:

1. 保留原搜索条件

2. 二级菜单 

3. 导航条 

4. 权限组件【使用文档】

内容详细:
1. 保留原搜索条件【独立】

	实现代码:
		simple_tag,目的是生成跳转的URL时,要携带当前的条件。
			例如:
				访问此地址 http://127.0.0.1:8000/crm/depart/list/?page=7,那么编辑和删除的URL应该是:
					http://127.0.0.1:8000/crm/depart/edit/64/?_filter=page%3D7
					http://127.0.0.1:8000/crm/depart/del/64/?_filter=page%3D7
			
			@register.simple_tag
			def memory_url(request,name,*args,**kwargs):
				"""
				生成URL(含条件)
				:return:
				"""
				# /crm/depart/edit/45/?_filter=page=5&age=1
				base_url = reverse(name,args=args,kwargs=kwargs)
				if not request.GET:
					return base_url
				new_query_dict = QueryDict(mutable=True)
				new_query_dict['_filter'] = request.GET.urlencode() # _filter=pagesdf5sdfagesdfsdf1
				url = "%s?%s" % (base_url, new_query_dict.urlencode(),)
				return url
		
		视图调用函数生成原来的URL
			例如: 
				在添加/编辑/删除页面完成操作之后,调用此方法生成回到列表页面的URL。
				
			def memory_reverse(request,name,*args,**kwargs):
				"""
				反向生成带条件的URL
				:return:
				"""
				url = reverse(name,args=args,kwargs=kwargs)
				filter = request.GET.get('_filter')
				if not filter:
					return url
				return "%s?%s" % (url, filter,)
				


		在项目中应用时:
			在模板中:
				{% load crm %}
				<a href="{% memory_url request 'depart_edit' row.id %}"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
				
			在视图中:
				def depart_del(request,nid):
					"""
					删除部门
					:param request:
					:param nid:
					:return:
					"""
					models.Department.objects.filter(id=nid).delete()
					return redirect(memory_reverse(request, 'depart_list'))


2. 支持二级菜单 
	a. 表结构的修改 
		- 6张表 
	b. 支持菜单的数据结构
		[
			{'id':1,'title':'xx','url':'...'},
			{'id':1,'title':'xx','url':'...'},
			{'id':1,'title':'xx','url':'...'},
			{'id':1,'title':'xx','url':'...'},
		]
		
		
		[
			{
				id:1,
				title:'父菜单1',
				children:[
					{'id':1,'title':'部门列表','url':...},
					{'id':5,'title':'用户列表','url':...},
				]
				
			},
			{
				id:2,
				title:'父菜单2',
				children:[
					
				]
			},
		
		]
		
		
		RBAC组件:
			- 中间件 
			- 初始化函数 
			- filter/inclusion_tag
			
			- js 
			- css 
			
		
		补充:
			- 有序字典
			
	

3. 对于无法做菜单的权限,访问时,应该让那个菜单默认选中?
	

4. 导航条
	- 数据库自关联 
	- 反射 
	- inclusion_tag 
	

3. 权限组件【使用文档】
	
	1. 新项目创建一个Project【接口测试管理】
		
		
	2. 拷贝rbac app 到新项目中。
	
	3. 删除rbac/migrations目录下的所有问题(除__init__.py除外)
		
	
	4. 接口测试管理的表结构设计。
		
		- 用户表需要继承 rabc 中的用户表,例如:
							
			class UserInfo(AbstractUserInfo):
				"""
				用户表
				"""
				email = models.EmailField(verbose_name='邮箱')

		- settings中注册 app,例如:
			INSTALLED_APPS = [
				...
				'api.apps.ApiConfig',
				'rbac.apps.RbacConfig',
			]
					
		
		- 数据库迁移 
			
			
	5. 业务开发 
		
		- 将模板中 【动态生成菜单】 【导航条】 功能去掉。
			{% get_menu request %}
			
			{% get_breadcrumb request %}
		
		- API开发
			- 保留原搜索条件 
			- 分页 
			- 编辑/删除/添加 模板页面的重用。
			- ModelForm 定制BootStrap样式 
			- 错误信息中文显示 
		- 用户管理	
			..
		
	6. 使用 django admin进行权限信息的录入【权限信息】
		- 创建admin的超级用户
		- 权限分配
			- 菜单表
			- 权限表
			- 角色表
			- 权限角色关系表 
			
	7. 业务中添加用户管理【用户信息】
		- 用户增删改查 
		- 用户和角色关系 
		
		简单:admin 
			
							
		
	8. 用户登录
		- 视图函数示例:
			def login(request):
				if request.method == 'GET':
					return render(request, 'login.html')
				user = request.POST.get('username')
				pwd = request.POST.get('password')
				user_object = models.UserInfo.objects.filter(username=user, password=pwd).first()
				if not user_object:
					return render(request, 'login.html', {'error': '用户名或密码错误'})

				# 权限初始化
				init_permission(user_object,request)
				return redirect(reverse('index'))
			
		- HTML示例:
			<div style="width: 400px;margin: 0 auto;margin-top: 100px;">
				<form class="form-horizontal" method="post">
					{% csrf_token %}
					<div class="form-group">
						<label for="user" class="col-sm-3 control-label">用户名</label>
						<div class="col-sm-9">
							<input type="text" class="form-control" id="user" name="username">
						</div>
					</div>
					<div class="form-group">
						<label for="pwd" class="col-sm-3 control-label">密码</label>
						<div class="col-sm-9">
							<input type="password" class="form-control" id="pwd" name="password">
						</div>
					</div>
					<div class="form-group">
						<div class="col-sm-offset-3 col-sm-9">
							<button type="submit" class="btn btn-primary">登 录</button>
							<span style="color: red">{{ error }}</span>
						</div>
					</div>
				</form>
			</div>
		

		- settings.py 配置文件:
			- 保存权限信息:
				RBAC_SESSION_PERMISSION_KEY = 'asdfu3nrsluidfowljer'
			- 保存菜单信息:
				RBAC_SESSION_MENU_KEY = 'jJASHDIOywejhASD'


	9. 应用中间件
		- 白名单处理 
		- 免权限校验的URL
		- 权限校验 
		
		
		settings.py 
			# 中间件应用
			MIDDLEWARE = [
				....
				'rbac.middleware.rbac.RbacMiddleware'
			]
				
			# 白名单(无需登录/无需权限校验)
			RBAC_VALID_LIST = [
				'/api/login/',
				'/admin.*'
			]
			
			# 免校验(需登录/无需权限校验)
			RBAC_NO_PERMISSION_LIST = [
				'/api/index/'
			]
				
			# 父权限的名称(用于做菜单的默认展开)
			RBAC_CURRENT_PARENT_NAME = "dufs3sffdsdfsdf"
			# 导航条 
			RBAC_RECORD_LIST = "ffsf3fsdfsdf"

	10. 在 layout.html 中应用 动态菜单和导航条。
		
			{% get_menu request %}
			
			{% get_breadcrumb request %}

	11. 粒度控制到按钮
			{% extends 'layout.html' %}
			{% load api %}
			{% load rbac %}

			{% block content %}
			<div style="margin: 5px;">
				<div>
					{% if request|has_permission:'interface_add' %}
						<a href="{% memory_url request 'interface_add' %}" class="btn btn-primary">添加</a>
					{% endif %}
				</div>
				<table class="table table-bordered">
					<thead>
						<tr>
							<th>序号</th>
							<th>接口名称</th>
							<th>URL</th>
							{% if request|has_permission:'interface_edit' or request|has_permission:'interface_delete' %}
							<th>选项</th>
							{% endif %}
						</tr>
					</thead>
					<tbody>
						{% for row in queryset %}
							<tr>
								<td>{{ forloop.counter }}</td>
								<td>{{ row.title }}</td>
								<td>{{ row.url }}</td>
								{% if request|has_permission:'interface_edit' or request|has_permission:'interface_delete' %}
								<td>
									{% if request|has_permission:'interface_edit' %}
										<a href="{% memory_url request 'interface_edit' row.id %}">编辑</a>
									{% endif %}
									{% if request|has_permission:'interface_delete' %}
										<a href="{% memory_url request 'interface_delete' row.id %}">删除</a>
									{% endif %}
								</td>
								{% endif %}
							</tr>
						{% endfor %}
					</tbody>

				</table>

				<ul class="pagination">
					  {{ pager.page_html|safe }}
				  </ul>
			</div>

			{% endblock %}
	
	
总结:
	- ModelForm 
		- 手写:样式 & 错误信息   
		- 重写 __init__ 方法 + 使用super 调用父类的 __init__方法 
		- 配置文件:zh-hans  
		- 自定义钩子方法:
			def clean_字段名(..):
				pass 
		注意:编辑时应该加入一个 instance 参数。 
		
		
	- 数据库中如果有 choice ,在模板中显示中文 
		
		gender = models.CharField(verbose_name='性别',choices=((1,'男'),(2,'女')))
		
		- obj.get_gender_display()
		
	
	- django请求生命周期 
	
	
	- 中间件的应用 
	
	
	- django配置文件 
		- from 项目 import settings 		【用户定义】
		- from django.conf import settings  【用户定义】+ Django内置配置 
		
		注意:配置文件中的值必须要大写 
		
	- 正则表达式 + re.match 模块 
	
	
	- 反射 
		setattr(request,'xxxxxxxxx',1) # request.xxxxxxxxx = 1 
		
	- 不能为空 
		... filter(字段__isnull = False)
		
	- 去重 
		... filter(字段__isnull = False).distinct()
		
	- ORM中Model表进行自关联 
		
		
	- 有序字典 (OrderdDict)
	
	- django中的session会对用户赋值的数据进行序列化再保存
	
		request.session['k1'] = {'xxx':123}   # 正确 
		request.session['k1'] = QuerySet()    # 错误
		
	- 自定义模板方法 
		- simple_tag, 记录原搜索条件
		- filter,粒度到按钮控制
		- inclusion_tag ,动态生成菜单+导航条 
		
	- 记录原搜索条件
		- memory_url
		- memory_reverse 
		
	- 分页 
	
	- django admin  
		- 创建用户 
		- admin中显示中文表名称 
			class Menu(models.Model):
				"""
				菜单表
				"""
				title = models.CharField(verbose_name='菜单',max_length=32)
				icon = models.CharField(verbose_name='图标',max_length=32)

				def __str__(self):
					return self.title

				class Meta:
					verbose_name_plural = '菜单表'
		- 定制admin中显示的列 
			class MenuAdmin(admin.ModelAdmin):
				list_display = ['title','icon']
			admin.site.register(models.Menu,MenuAdmin)
						
		
	- ORM中创建“抽象类” abstract = True
	
		class AbstractUserInfo(models.Model):
				"""
				用户表
				"""
				username = models.CharField(verbose_name='用户名', max_length=32)
				password = models.CharField(verbose_name='密码', max_length=64)
				roles = models.ManyToManyField(verbose_name='拥有的角色',to=Role)

				class Meta:
					abstract = True # 当前类不会再数据库迁移时候生成相关的表了,他来当 “基类”,给业务表中的用户表使用

猜你喜欢

转载自blog.csdn.net/weixin_41765871/article/details/84532032
今日推荐