Django 框架中的自定义模板标签(template.Library())

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012605477/article/details/80742366

某一些标签(例如:菜单栏、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权限相关的作者代码类似,本人对其进行了再加工。

django 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博主的代码,特此声明下。




猜你喜欢

转载自blog.csdn.net/u012605477/article/details/80742366
今日推荐