某一些标签(例如:菜单栏、css、JS、以及一些复杂计算后的数据等)需要我们自定义。
然后再在指定的html中引用并显示。
之所以要用到标签,主要作用就是想让一些内容在多个模板(HTML)中都要有,比如菜单栏。
我们绝对不想在每个视图函数(views中)都写一次这些变量内容。
即每个页面都需要用到info,若,每个视图函数都写一次,那真的是所非常痛苦,所以要说一下Django的上下文渲染器。
例如:(代码取自自强学堂)
from django.shortcuts import render
def home(request):
return render(request, 'home.html', {'info': 'Welcome to ziqiangxuetang.com !'})
在Html中使用就要这样写:
{{ info }}
1.首先创建一个py文件,名字为myTag.py,然后引入template包
from django import template
#注册我们自定义的标签,只有注册过的标签,系统才能认识你,这是固定写法
register = template.Library()
2.添加标签相关的方法:
标签相关方法指的是在html显示前,后台先进行预处理,和我们平常的方法相同,只不过这个方法是针对标签所定义的:
# 用户请求views中的视图函数后,在试图函数中调用的方法,即在session中写入菜单-权限相关数据
def get_structure_data(request):
"""处理菜单结构"""
menu = request.session[settings.SESSION_MENU_KEY]
all_menu = menu[settings.ALL_MENU_KEY]
permission_url = menu[settings.PERMISSION_MENU_KEY]
# 定制数据结构
all_menu_dict = {}
for item in all_menu:
item['status'] = False
item['open'] = False
item['children'] = []
all_menu_dict[item['id']] = item
request_rul = request.path_info
for url in permission_url:
# 添加两个状态:显示 和 展开
url['status'] = True
pattern = url['url']
if re.match(pattern, request_rul):
url['open'] = True
else:
url['open'] = False
# 将url添加到菜单下
all_menu_dict[url['menu_id']]["children"].append(url)
# 显示菜单:url 的菜单及上层菜单 status: true
pid = url['menu_id']
while pid:
all_menu_dict[pid]['status'] = True
pid = all_menu_dict[pid]['parent_id']
# 展开url上层菜单:url['open'] = True, 其菜单及其父菜单open = True
if url['open']:
ppid = url['menu_id']
while ppid:
all_menu_dict[ppid]['open'] = True
ppid = all_menu_dict[ppid]['parent_id']
# 整理菜单层级结构:没有parent_id 的为根菜单, 并将有parent_id 的菜单项加入其父项的chidren内
menu_data = []
for i in all_menu_dict:
if all_menu_dict[i]['parent_id']:
pid = all_menu_dict[i]['parent_id']
parent_menu = all_menu_dict[pid]
parent_menu['children'].append(all_menu_dict[i])
else:
menu_data.append(all_menu_dict[i])
return menu_data
#将数据库中指定用户可显示的菜单-权限进行html拼装
def get_menu_html(menu_data):
option_str2 = '''
<li class="treeview {active}">
<a href="#"><i class="fa fa-link"></i><span>{menu_title}</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
{sub_menu}
</ul>
</li>
'''
url_str2 = """
<li class="{active}"><a href="{permission_url}"><i class="fa"></i><i class="fa fa-circle-o"></i><span>{permission_title}</span></a></li>
"""
menu_html = ''
for item in menu_data:
if not item['status']: # 如果用户权限不在某个菜单下,即item['status']=False, 不显示
continue
else:
if item.get('url'): # 说明循环到了菜单最里层的url
menu_html += url_str2.format(permission_url=item['url'],
active="active" if item['open'] else "",
permission_title=item['title'])
else:
if item.get('children'):
sub_menu = get_menu_html(item['children'])
else:
sub_menu = ""
menu_html += option_str2.format(menu_title=item['title'],
sub_menu=sub_menu,
active="active" if item['open'] else "",)
return menu_html
以上代码和csdn上的一个写rbac权限相关的作者代码类似,本人对其进行了再加工。
3.添加自定义标签,菜单栏、css、js、登录用户的用户名都需要多页面使用。
所以定义了下面标签方法(本人未使用下面的css和js标签)
@register.simple_tag
def rbac_menu(request):
"""
显示多级菜单:请求过来 -- 拿到session中的菜单,权限数据 -- 处理数据 -- 作显示
返回多级菜单:数据处理部分抽象出来由单独的函数处理;渲染部分也抽象出来由单独函数处理
:param request:
:return:
"""
menu_data = get_structure_data(request)
menu_html = get_menu_html(menu_data)
return mark_safe(menu_html)
@register.simple_tag
def rbac_css():
"""
rabc要用到的css文件路径,并读取返回;注意返回字符串用mark_safe,否则传到模板会转义
:return:
"""
css_path = os.path.join('rbac', 'style_script', 'rbac.css')
css = open(css_path, 'r', encoding='utf-8').read()
return mark_safe(css)
@register.simple_tag
def rbac_js():
"""
rabc要用到的js文件路径,并读取返回
:return:
"""
js_path = os.path.join('rbac', 'style_script', 'rbac.js')
js = open(js_path, 'r', encoding='utf-8').read()
return mark_safe(js)
@register.simple_tag
def rbac_loginUser(request):
return mark_safe(request.session['name'])
4.在base.html中使用上述标签.
下面body中的内容就是我们所想要的内容,其他页面只要继承base.html就都具有了该标签的数据:
{% load myTag%}
{% load staticfiles %}
{#<!DOCTYPE html>#}
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}XXXXX{% endblock %}</title>
{% block head_link %}{% endblock %}
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{% static '/bower_components/bootstrap/dist/css/bootstrap.min.css' %}">
<!-- 子模板的样式表应放在父模板的样式表之后,只有这样才可以在子模板中重定义父模板中的某些样式 -->
{% block styles %}{% endblock %}
</head>
<body>
{% rbac_loginUser request %}
{% rbac_menu request %}
</body>
</html>
其他页面要继承时,加上下面的语句即可:
{% extends "base.html" %}
上述代码整合了多个csdn博主的代码,特此声明下。