一、权限分配
1、保留原搜索条件
问题描述: 当我们在用户管理系统中查看不同的一级菜单下面的二级菜单时候,会产生不同的搜索条件,在有搜索条件的情况下我们对权限进行操作后再回到首页的时候应该保留原有的搜索条件
比如在这种情况下我们任意操作,再回到此页面的时候应该也保存改操作。
思路: 搜索条件是根据url中的get数据来实现的,我们在进行操作的时候获取到url中的数据,再次返回时再加上get数据即可
1 <div class="col-md-3">
2 <div class="panel panel-default">
3 <!-- Default panel contents -->
4 <div class="panel-heading">
5 <i class="fa fa-book" aria-hidden="true">一级菜单</i>
6 <a href="{% memory_url request 'rbac:menu_add' %}" class="right btn btn-success btn-xs" style="padding:2px 8px; margin: -3px;">
7 <i class="fa fa-plus-circle" aria-hidden="true">新建</i>
8 </a>
9 </div>
10 <!-- Table -->
11 <table class="table">
12 <thead>
13 <tr>
14 <th>名称</th>
15 <th>图标</th>
16 <th>选项</th>
17 </tr>
18 </thead>
19 <tbody>
20 {% for foo in obj %}
21 <tr class="{% if mid == foo.id|safe %}
22 active
23 {% endif %}">
24 <td >
25 <a href="?mid={{ foo.id }}">{{ foo.title }}</a>
26 </td>
27 <td>
28 <i class="fa {{ foo.icon }}"></i>
29 </td>
30 <td>
31 <a style="color:#333333;" href="{% memory_url request 'rbac:menu_edit' pid=foo.id %}">
32 <i class="fa fa-edit" aria-hidden="true"></i>
33 </a> |
34 <a style="color:#d9534f;" href="{% memory_url request 'rbac:menu_del' pid=foo.id %}">
35 <i class="fa fa-trash-o"></i>
36 </a>
37 </td>
38 </tr>
39 {% endfor %}
40 </tbody>
41 </table>
42 </div>
43 </div>
- 我们看到,在模版中 每个一级菜单的名称属性是一个 a 标签,在a标签的href属性中:href=?mid={{foo.id}} 这样在我们浏览器端显示的就是每一个标签的a标签后面添加了每个对象的id
而在模版中根据后端传过来的mid可以对当前点击的mid和对象id是否一致而添加active属性,实现提示当前点击效果
- 通过后端获取到url中mid=2,并传递到前端模版中进行比对,找到id=2的对象后添加active属性完成效果
当我们了解搜索条件的原理后我们就可以实现保留搜索条件了
- 在已有url条件的情况下如何在后端保留搜索条件
在添加、编辑等a标签中把url中的信息一起带上,也就是当搜索条件不同的时候,添加按钮的href链接自然也不相同,在完成添加后重定向的时候再把url信息加到重定向后面就能实现保留原搜索条件了
注意:如果我们直接在url后面添加参数的话会和当前页面的url参数混淆(刚好当前页面的get参数和你保留原搜索条件相同),那我们就需要给搜索条件添加一个key,values=搜索条件,把搜索条件当成一个整体,这样在重定向的时候直接拿取搜索条件
自定义一个simple_tag, 功能是生成url并且带上参数
from django.http import QueryDict # QueryDict 用于打包数据
@register.simple_tag
def memory_url(request, url)
"""
生成带有原搜索条件的url,(替代了模版中的{% url %})
"""
basic_url =reverse(url)
if not request.GET:
# 表示没有搜索条件,直接返回url
return basic_url
query_dict = QueryDict(mutable=True)
query_dict['_filter'] = request.GET.urlencode() # get 后面参数通过urlencode获取
return '%s?%s' (basic_url, query_dict.urlencode())
这样在前端模版中将 a 标签的href={% memory_url request 'rbac:menu_list %} 就会动态根据搜索条件生成url,这样跳转的时候就会带上原搜索条件
在重定向的时候再根据搜索条件拼接url即可
1 def memory_reverse(request, name):
2 url = reverse(name)
3 origin_params = request.GET.get('_filter')
4 if origin_params:
5 url = '%s?%s' % (url, origin_params)
6 return url
2、ModelForm同时对用户输入和默认值进行修改
我们在crm系统中,对权限进行添加的时候,前提是已经选好了二级菜单。 在选好二级菜单的前提下新建权限,该权限就应该默认属于选中的二级菜单下面,用户无法改变,所以我们在利用ModelForm进行数据库操作的时候,就应该结合用户输入与默认值一起对数据库操作
- 利用ModelForm的instance 指定字段
1 def permission_menu_add(request, second_id):
2 if request.method == 'GET':
3 form = PermissionModelForm()
4 return render(request, 'rbac/change.html', {'form': form})
5 form = PermissionModelForm(data=request.POST)
6 if form.is_valid():
# 前面都是正常流程,到这里通过了校验以后
7 second_menu_obj = models.Permissions.objects.filter(id=second_id).first() # 拿到他的二级菜单对象
8 if not second_menu_obj:
9 return render(request, '404.html')
10 form.instance.pid = second_menu_obj # 指定instance的pid 为二级菜单对象后再save
11 form.save()
12 return redirect(memory_reverse(request, 'rbac:menu_list'))
13 return render(request, 'rbac/change.html', {'form': form})
3、在添加二级菜单的时候,根据添加时选中的一级菜单,默认属于该菜单下,但应许用户进行修改,所以在添加页面应该有默认值
- 通过ModeForm的initial值完成默认显示
1 def second_menu_add(request, menu_id):
2 obj = models.Menu.objects.filter(id=menu_id).first() # 先拿到相对于的一级菜单对象
3 if request.method == 'GET':
4 form = SecondMenuModelForm(initial={'menu': obj}) # initial={'menu': obj} menu为应该默认的选项
5 return render(request, 'rbac/change.html', {'form': form})
4、利用基类统一form的格式
在crm项目中教多form表,根据bootstrap的样式,需要在表单加上form-contral 后表单比较美观,这样我们每个ModelForm都需要手动添加,那我们可以利用基类定制,然后每个ModelForm都继承基类即可。
1 class BootStrapModelForm(forms.ModelForm): 2 3 def __init__(self, *args, **kwargs): 4 super(BootStrapModelForm, self).__init__(*args, **kwargs) 5 # 统一给ModelForm生成字段添加样式 6 for name, field in self.fields.items(): 7 field.widget.attrs['class'] = 'form-control'
# 后面的ModelForm直接继承该类即可
class PermissModelForm(BootStrapModelForm):
class Meta:
........
这样就避免了重复写__init__方法