价格策略
到这个地步, 价格策略的CURD, 无它, 唯手熟尔!!
# 删除代码优化
删除的代码进行了优化. 像客户删除和价格策略的删除都是一样的逻辑. 往后再写其他功能的删除就变得简单啦!!
1> <tr row-id="{{ row.id }}">
<a cid="{{ row.id }}" class="btn btn-danger btn-xs btn-delete" href="#">删除</a>
2> {% include 'include/delete_modal.html' %}
3> {% block js %}
<script>
let DELETE_ID;
let DELETE_URL = "{% url 'policy_delete' %}"
</script>
<script src="{% static 'js/delete_modal.js' %}"></script>
{% endblock %}
4> 在后端代码中,根据业务需求做逻辑删除或物理删除,返回的是json数据!
另外,在价格策略的页面也可以加上搜索的功能..略.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 删除关键代码
web/views/policy.py
from django import forms
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from utils.bootstrap import BootStrapForm
from utils.pager import Pagination
from utils.response import BaseResponse
from web import models
class PolicyModelForm(BootStrapForm, forms.ModelForm):
class Meta:
model = models.PricePolicy
fields = "__all__"
def policy_list(request):
queryset = models.PricePolicy.objects.all().order_by("count") # 无逻辑删除;数量从小到大排
obj = Pagination(request, queryset)
# context = {
# 'queryset': obj.current_page_queryset,
# 'pager_string': obj.html,
# }
# return render(request, "policy_list.html", context)
return render(request, "policy_list.html", {"obj": obj})
def policy_add(request):
if request.method == "GET":
form = PolicyModelForm(initial={'price': ''})
return render(request, 'form.html', {'form': form})
form = PolicyModelForm(data=request.POST)
if not form.is_valid():
return render(request, 'form.html', {'form': form})
form.save()
return redirect(reverse("policy_list"))
def policy_edit(request, pk):
instance = models.PricePolicy.objects.filter(id=pk).first()
if request.method == "GET":
form = PolicyModelForm(instance=instance)
return render(request, 'form.html', {'form': form})
form = PolicyModelForm(data=request.POST, instance=instance)
if not form.is_valid():
return render(request, 'form.html', {'form': form})
form.save()
return redirect(reverse("policy_list"))
def policy_delete(request):
res = BaseResponse(status=True)
cid = request.GET.get('cid') # 可对cid进行判断!!
models.PricePolicy.objects.filter(id=cid).delete()
return JsonResponse(res.dict)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
web/templates/policy_list.html
{% extends 'layout.html' %}
{% load static %}
{% block content %}
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="{% url 'policy_add' %}">
<span class="glyphicon glyphicon-plus-sign"></span>
新建
</a>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>数量</th>
<th>价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for row in obj.current_page_queryset %}
<tr row-id="{{ row.id }}">
<td>{{ row.id }}</td>
<td>{{ row.count }}</td>
<td>{{ row.price }}</td>
<td>
<a class="btn btn-primary btn-xs" href="{% url 'policy_edit' pk=row.id %}">编辑</a>
<a cid="{{ row.id }}" class="btn btn-danger btn-xs btn-delete" href="#">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="Page navigation">
<ul class="pagination">
{{ obj.html }}
</ul>
</nav>
{% include 'include/delete_modal.html' %}
{% endblock %}
{% block js %}
<script>
let DELETE_ID;
let DELETE_URL = "{% url 'policy_delete' %}"
</script>
<script src="{% static 'js/delete_modal.js' %}"></script>
{% endblock %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
web/templates/include/delete_modal.html
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<h4>是否确定要删除?</h4>
<p>Eliminate human tyranny, the world belongs to the three-body.</p>
<p>
<button type="button" class="btn btn-danger" id="btnConfirmDelete">确 定</button>
<button type="button" class="btn btn-default" id="btnCancelDelete">取 消</button>
<span style="color: brown" id="deleteError"></span>
</p>
</div>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
web/static/js/delete_modal.js
$(function () {
bindDeleteEvent();
bindConfirmDeleteEvent(); // 确认删除
});
function bindDeleteEvent() {
// 触发点击事件,对话框显示
$(".btn-delete").click(function () {
$("#deleteError").empty(); // 先删除对话框里的错误信息
$("#deleteModal").modal("show");
DELETE_ID = $(this).attr("cid")
});
// 点击点击事件,对话框消失
$("#btnCancelDelete").click(function () {
$("#deleteModal").modal('hide');
});
}
function bindConfirmDeleteEvent() {
$("#btnConfirmDelete").click(function () {
// 举个例子,ajax发送get请求 /customer/delete/?cid=2
$.ajax({
url: DELETE_URL,
type: "GET",
data: {cid: DELETE_ID},
dataType: "JSON",
success: function (res) {
if (res.status) {
// -- 删除成功
// 方式一:页面的刷新
// location.reload();
// 方式二:在tr标签上自定义row-id属性 便于找到当前数据行,删除
$("tr[row-id='" + DELETE_ID + "']").remove();
$("#deleteModal").modal('hide'); // 删除后,对话框消失
} else {
// -- 删除失败,错误信息在页面展示.
$("#deleteError").text(res.detail);
}
}
})
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 权限粒度-按钮
权限的粒度控制在按钮级别, 根据是否是否具有权限来决定是否展示按钮. - 即没权限就看不见!
该按钮的代码不存在,不就显示不了嘛.基本逻辑如下:
(使用@register.simple_tag())
1.获取当前登录用户的角色
2.根据角色获取他所有的权限字典
3.判断是否具有权限
若无权限,返回空字符串; 有权限,返回HTML代码
★ 注意一个细节:
当该角色没有编辑和删除的权限.表格操作这一栏是为空的.若需求允许这样展示,那么无可厚非.
当然若无编辑和删除的权限,也可以让操作这一列消失在页面上. 需要对表格中相应的表头<tr>和表项<td>进行设置.
- 用@register.simple_tag()来实现?
在模版中传入request、编辑和删除的权限对应的两个url_name,simple_tag对应的函数接受,判断有无权限,返回True/False.
模版中通过模版语法if进行判断,进而控制是否展示?
NO!!模版语法if不支持simple_tag!!
- 那如何是好?用@register.filter 因为模版语法if是支持filter的!!
但要知道使用filter,它最多只能支持传入两个参数.. So,我们需要进行构造!! Ps:我试过了,用列表和元祖传递两个url_name模版语法不支持.
{% if request|is_column:"customer_edit,customer_delete" %}
<td>
{% edit_permission request 'customer_edit' pk=row.id %}
{% del_ajax_permission request 'customer_delete' pk=row.id %}
</td>
{% endif %}
我自己进行了改进,避免多次调用is_column,在模版中将结果存储到一个临时变量中使用!!
{% with is_show=request|is_column:"customer_edit,customer_delete" %}
{% if is_show %}<th>...</th>{% endif %} # th也需要判断
{% if is_show %}<td>...</td>{% endif %}
{% endwith %}
△ 注意: 客户管理和价格策略管理的删除都是基于Ajax的,html代码一样;但级别管理的删除是基于form表单的,跟它两不一样.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
关键代码如下:
from django import template
from django.conf import settings
from django.urls import reverse
from django.utils.safestring import mark_safe
register = template.Library()
def check_permission(request, name):
"""判断当前角色有无该权限"""
# 1.获取当前登录用户的角色
role = request.nb_user.role
# 2.根据角色获取他所有的权限字典
permission_dict = settings.NB_PERMISSION[role]
if (name in permission_dict) or (name in settings.NB_PERMISSION_PUBLIC):
return True
@register.simple_tag()
def add_permission(request, url_name, *args, **kwargs):
# 判断是否具有权限
# 若无权限,返回空; 有权限,返回HTML代码
if not check_permission(request, url_name):
return ""
url = reverse(url_name, args=args, kwargs=kwargs) # 根据url_name反向生成url
tpl = """
<a class="btn btn-success" href="{}">
<span class="glyphicon glyphicon-plus-sign"></span>
新建
</a>
""".format(url)
return mark_safe(tpl)
@register.simple_tag()
def edit_permission(request, url_name, *args, **kwargs):
if not check_permission(request, url_name):
return ""
url = reverse(url_name, args=args, kwargs=kwargs) # 根据url_name反向生成url
tpl = """
<a class="btn btn-primary btn-xs" href="{}">
编辑
</a>
""".format(url)
return mark_safe(tpl)
@register.simple_tag
def del_form_permission(request, name, *args, **kwargs):
if not check_permission(request, name):
return ""
url = reverse(name, args=args, kwargs=kwargs)
tpl = """
<a class="btn btn-danger btn-xs" href="{}">
删除
</a>
""".format(url)
return mark_safe(tpl)
@register.simple_tag()
def del_ajax_permission(request, url_name, *args, **kwargs):
if not check_permission(request, url_name):
return ""
pk = kwargs["pk"]
tpl = """
<a href="#" cid="{}" class="btn btn-danger btn-xs btn-delete">删除</a>
""".format(pk)
return mark_safe(tpl)
@register.filter
def is_column(request, others):
"""是否展示`操作`这一列"""
name_list = others.split(',')
# 但凡操作这一列 的编辑和删除权限 有其一,都应展示操作这一列
for name in name_list:
if check_permission(request, name):
return True
return False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
展望:
可以看到 level_list.html、customer_list.html、policy_list.html 页面百分之80都是一样的!! 很多都是复制粘贴的.
想要进行优化,将这几个页面公共起来, 具体的得要学习 stark 组件 参照的是Django-admin的源码!! (つД`)ノ
# 跳转携带条件
修改第9页的客户的数据,修改完成后,返回的客户列表也在第9页.
在搜索框输入dc, 点击第9页的数据. 此时url: http://127.0.0.1:8000/customer/list/?keyword=dc&page=9
点击某条数据的编辑按钮. 此时url: http://127.0.0.1:8000/customer/edit/92/?_filter=keyword%3Ddc%26page%3D9
修改完后, 返回的页面url: http://127.0.0.1:8000/customer/list/?keyword=dc&page=9
注意: 之所以跳转编辑界面的url携带的上一个页面的参数 用_filter来指代, 是为了避免 跳转编辑界面的url会自己传递参数.
比如: `http://127.0.0.1:8000/customer/edit/92/?xxx=111&keyword=dc&page=9`
修改完后,返回客户列表页面.视图函数customer_edit的逻辑.
- return redirect(reverse("customer_list")) 肯定不行!
- 需要获取跳转编辑页面前的参数,xxx=111&keyword=dc&page=9 + 路由反转reverse("customer_list") 进行拼接
No!!虽然能实现,但我们应该将非客户列表页面的参数剔除掉!! 是没办法很好的解决的,特别是参数很多的情况!
- So,获取跳转编辑页面前url中的参数要用_filter来指代!!在视图函数中 request.GET.get("_filter") 就取到啦!!
Ps: Django-admin的源码中就是这么做的!
级别管理、客户管理、价格策略管理对应的修改视图,其最后跳转的地方都需要进行修改下!
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
关键代码如下:
@register.simple_tag()
def edit_permission(request, url_name, *args, **kwargs):
if not check_permission(request, url_name):
return ""
url = reverse(url_name, args=args, kwargs=kwargs) # 根据url_name反向生成url
# !! 这里主要用到了 QueryDict(mutable=True) 即request.GET是一个QueryDict对象!
param = request.GET.urlencode() # keyword=dc&page=9 没有返回的是""
if param:
new_query_dict = QueryDict(mutable=True)
new_query_dict['_filter'] = param # <QueryDict: {'_filter': ['keyword=dc&page=9']}>
# 会自动进行url的转义!!
filter_string = new_query_dict.urlencode() # _filter=keyword%3Ddc%26page%3D9
tpl = """<a href="{}?{}" class="btn btn-primary btn-xs">编辑</a>""".format(url, filter_string)
return mark_safe(tpl)
tpl = """<a class="btn btn-primary btn-xs" href="{}">编辑</a>""".format(url)
return mark_safe(tpl)
"""
视图函数里的修改
"""
def filter_reverse(request, url):
filter_string = request.GET.get("_filter")
if not filter_string:
return url
return "{}?{}".format(url, filter_string)
def customer_edit(request, pk):
""" 修改客户 """
... ... ...
"""
return redirect(reverse("customer_list"))
"""
return redirect(filter_reverse(request, reverse("customer_list")))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35