day14 订单管理系统
1.关于登录
1.1 UI美化
页面美化,用BootStrap + 自定义BooStrapForm类实现。
class BootStrapForm:
exclude_filed_list = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# {'title':对象,"percent":对象}
for name, field in self.fields.items():
if name in self.exclude_filed_list:
continue
field.widget.attrs['class'] = "form-control"
field.widget.attrs['placeholder'] = "请输入{}".format(field.label)
1.2 csrf问题
/**
* 根据cookie的name获取对应的值
* @param name
* @returns {null}
*/
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFTOKEN", getCookie('csrftoken'));
}
}
})
在页面上引入即可:
<script src="{% static 'js/csrf.js' %}"></script>
2.中间件校验
2.1 是否登录
NB_WHITE_URL = ['/login/', '/sms/login/', '/sms/send/']
class AuthMiddleware(MiddlewareMixin):
def is_white_url(self, request):
if request.path_info in settings.NB_WHITE_URL:
return True
def process_request(self, request):
""" 校验用户是否已登录 """
# 1.不需要登录就能访问的URL
if self.is_white_url(request):
return
# 2.session中获取用户信息,能获取到登录成功;未登录
# {'role': mapping[role], 'name': user_object.username, 'id': user_object.id}
user_dict = request.session.get(settings.NB_SESSION_KEY)
# 3.未登录,跳转回登录页面
if not user_dict:
return redirect(settings.NB_LOGIN_URL)
# 4.已登录,封装用户信息
request.nb_user = UserInfo(**user_dict)
2.2 是否有权限
class AuthMiddleware(MiddlewareMixin):
def process_view(self, request, callback, callback_args, callback_kwargs):
if self.is_white_url(request):
return
current_name = request.resolver_match.url_name
# 1.根据用户角色获取自己具备所有的权限
user_permission_dict = settings.NB_PERMISSION[request.nb_user.role]
# 2.获取当前用户访问的URL
current_name = request.resolver_match.url_name
# 3.判断是否在自己具备的权限
if current_name not in user_permission_dict:
# return HttpResponse("无权访问")
# print(request.Meta)
from django.core.handlers.wsgi import WSGIRequest
# print(request,type(request))
if request.is_ajax():
return JsonResponse({'status': False, 'detail': "无权访问"})
else:
return render(request, 'permission.html')
NB_PERMISSION = {
"ADMIN": {
"level_list": {"text": "级别列表", 'parent': None},
"level_add": {"text": "新建级别", 'parent': 'level_list'},
"level_edit": {"text": "编辑级别", 'parent': 'level_list'},
"level_delete": {"text": "删除级别", 'parent': 'level_list'},
"customer_list": {"text": "客户列表", 'parent': None},
"customer_add": {"text": "新建客户", 'parent': 'customer_list'},
"customer_edit": {"text": "编辑客户", 'parent': 'customer_list'},
"customer_delete": {"text": "删除客户", 'parent': 'customer_list'},
"customer_reset": {"text": "重置密码", 'parent': 'customer_list'},
"customer_charge": {"text": "我的交易记录", 'parent': 'customer_list'},
"customer_charge_add": {"text": "创建交易记录", 'parent': 'customer_list'},
"policy_list": {"text": "价格策略", 'parent': None},
"policy_add": {"text": "创建价格策略", 'parent': 'policy_list'},
"policy_edit": {"text": "编辑价格策略", 'parent': 'policy_list'},
"policy_delete": {"text": "删除价格策略", 'parent': 'policy_list'},
"transaction_list": {'text': "交易记录", 'name': "transaction_list", 'parent': None},
},
"CUSTOMER": {
"my_order_list": {"text": "订单列表", 'parent': None},
"my_order_add": {"text": "订单列表", 'parent': 'my_order_list'},
"my_order_cancel": {"text": "订单列表", 'parent': 'my_order_list'},
"my_transaction_list": {"text": "我的交易记录", 'parent': None},
}
}
3.路径导航
推荐:用inclusion_tag在页面渲染时生成。
# ...
# ....
text_list = [] # ["创建订单","订单列表"]
# 1.先添加当前访问的路径导航名称添加text_list
text_list.append(user_permission_dict[current_name]['text'])
# 2.循环获取上级
menu_name = current_name
while user_permission_dict[menu_name]['parent']:
menu_name = user_permission_dict[menu_name]['parent']
text = user_permission_dict[menu_name]['text']
text_list.append(text)
# 3.添加首页
text_list.append("首页")
# 4.翻转
text_list.reverse()
# 5.路径导航列表(用于后续页面显示)
request.nb_user.text_list = text_list
{% if request.nb_user.text_list %}
<ol class="breadcrumb">
{% for text in request.nb_user.text_list %}
<li><a>{{ text }}</a></li>
{% endfor %}
</ol>
{% endif %}
4.动态菜单
NB_MENU = {
'ADMIN': [
{
'text': "用户信息",
'icon': "fa-bed",
'children': [
{'text': "级别管理", 'url': "/level/list/", 'name': "level_list"},
{'text': "客户管理", 'url': "/customer/list/", 'name': "customer_list"},
{'text': "价格策略", 'url': "/policy/list/", 'name': "policy_list"},
]
},
{
'text': "交易管理",
'icon': "fa-bed",
'children': [
{'text': "交易记录", 'url': "/transaction/list/", 'name': "transaction_list"},
]
},
],
'CUSTOMER': [
{
'text': "订单中心",
'icon': "fa-bed",
'children': [
{'text': "订单管理", 'url': "/my/order/list/", 'name': "my_order_list"},
{'text': "我的交易记录", 'url': "/my/transaction/list/", 'name': "my_transaction_list"},
]
},
],
}
from django.http import QueryDict
from django.template import Library
from django.conf import settings
import copy
register = Library()
@register.inclusion_tag("tag/nb_menu.html")
def nb_menu(request):
# 1.读取当前用户的角色信息
# print(request.nb_user.role)
# 2.菜单信息
user_menu_list = copy.deepcopy(settings.NB_MENU[request.nb_user.role])
for item in user_menu_list:
# item['class'] = 'hide'
for child in item['children']:
# if child['url'] == request.path_info: # v1版
if child['name'] == request.nb_user.menu_name:
child['class'] = 'active'
# item['class'] = ""
return {'menu_list': user_menu_list}
<div class="multi-menu">
{% for item in menu_list %}
<div class="item">
<div class="title">
<span class="icon-wrap"><i class="fa {{ item.icon }}"></i></span> {{ item.text }}
</div>
<div class="body {{ item.class }}">
{% for child in item.children %}
<a class="{{ child.class }}" href="{{ child.url }}">{{ child.text }}</a>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
.multi-menu .item {
background-color: white;
}
.multi-menu .item > .title {
padding: 10px 5px;
border-bottom: 1px solid #dddddd;
cursor: pointer;
color: #333;
display: block;
background: #efefef;
background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa));
background: -ms-linear-gradient(bottom, #efefef, #fafafa);
background: -o-linear-gradient(bottom, #efefef, #fafafa);
filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')";
box-shadow: inset 0 1px 1px white;
}
.multi-menu .item > .body {
border-bottom: 1px solid #dddddd;
}
.multi-menu .item > .body a {
display: block;
padding: 5px 20px;
text-decoration: none;
border-left: 2px solid transparent;
font-size: 13px;
}
.multi-menu .item > .body a:hover {
border-left: 2px solid #2F72AB;
}
.multi-menu .item > .body a.active {
border-left: 2px solid #2F72AB;
}