Django 框架中的自定義模板標籤(template.Library())
阿新 • • 發佈:2018-11-27
某一些標籤(例如:選單欄、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博主的程式碼,特此宣告下。