20190325 Django自定义过滤器和自定义模板标签

代码布局(死去活来)

自定义要先解决几个问题:

1). 在哪里定义,要将代码写在哪里?

  • app目录下的名为templatetags的文件夹,必须叫这个名字。这个文件夹必须是一个python的包(python package),这个文件夹下一定有一个__init__.py的文件
  • 自定义的模板标签,或模板过滤器就放在这个包下的python模块中(python脚本文件)
  • app必须在settings中被注册

I.自定义模板过滤器

定义
  • 自定义过滤器就是一个python函数,它有1个或2个参数。

    • 第一个参数就是那个传进来的模板变量
    • 第二个参数是一个普通参数,可以是默认参数,也可以不要这个参数
  • 依旧以teacher应用的案例为例子:如何将性别从男1女0的二进制显示变成我们看得懂的汉字或者英文字男male女female呢?简言之,就是接收0和1,返回女和男

注册并定义一个过滤器:
from django.template import Library

register = Library()  # 必须用register这个变量名

def my_male(value):
    '''
    转换性别的过滤器
    :param value:
    :return:
    '''
    map = {
        0:'女',
        1:'男'
    }

    return map[value]

register.filter(my_male)    # 注册自定义过滤器
在模板中使用
  • Step1. load标签,引入自定义的过滤器模块,也就是templatetags包里的那个python文件teacher_tags.py

    {% load teacher_filters %}

    ......

  • step2. 在表格tbody当中,写入在过滤器文件中定义好的过滤器名my_male,

    <td>{{ student.sex|my_male }}</td>

注意:新建了templatetags的文件夹,要重启一下django服务。

2个参数:

需求:有中英文双语显示性别,则可以传入两个参数:

    '''
    转换性别的过滤器
    :param value:
    :return:
    '''
    map = {
        'zh': {0:'女', 1:'男'},
        'en': {0:'Female', 1:'Male'},
    }

    return map[value][lang]
给变量命名

过滤器变量的名字可以根据实际需要自己定义,避免名字重复或者名字太长的情况。

比如把def my_male(value, lang):改成 def aaa(value, lang)

然后在模板html里面将原来的<td>{{ student.sex|my_male }}</td>改成<td>{{ student.sex|aaa }}</td>

II.自定义模板标签

干任何事情

标签类型

1. 简单标签

django.template.Library.simple_tag()

  • 接受许多参数,并根据输入的参数和外部信息,进行处理后返回结果

创建、注册简单标签

代码布局在templatetags目录下,新建一个teacher_tags.py的文件

from django.template import Library
from datetime import datetime

register = Library()  # 必须用register这个变量名,必须要写

def current_time(format_str='%Y-%m-%d %H:%M:%S'):
    """就输出当前时间"""
    return datetime.now().strftime(format_str)

#注册
register.simple_tag(current_time, name='current')

自定义标签定义当前时间并格式化并注册

在模板中使用

{% load teacher_tags %}
    .....
    <h1>学生列表</h1>
    <p>当前时间:{% current %}</p>

定义好的过滤器加载到模板当中

运行结果:

自定义标签显示当前时间浏览器访问学生列表页面

传值

{% current format_str= %}

自定义标签显示当前时间页面
运行结果:

自定义标签显示当前时间浏览器访问学生列表页面

另外,{% current '%Y-%m-%d' %}也一样能显示出年月日格式的当前时间

模板标签就是一个函数,跟普通函数的传参一样,可以传字符串、模板变量、关键字参数

再举个例子:
先在teacher应用目录下的views视图文件里,我们将上下文context函数中传入’format_str’:’%H:%M:%S’,

return render(request, 'teacher/student_list_page.html',
                  context={
                      'students':students,
                      'format_str': '%H:%M:%S',
                  })

再回到学生页面模板(也就是前端html页面)中,此时format_str则作为一个模板变量。

<p>当前时间:{% current format_str %}</p>

运行结果:
浏览器访问学生列表显示时分秒格式时间

使用上下文变量

在自定义标签中,使用当前模板中的所有的上下文变量context

def current_time(context, format_str='%Y-%m-%d %H:%M:%S'):
        
    return datetime.now().strftime(format_str)
    
register.simple_tag(current_time, name='current',takes_context=True)    

语法格式:context``````take_context组成一对

class=‘new_year’

III. 包含标签(装饰器)

定义

通过渲染另外一个模板展示数据,以后django admin就会用到这个

@register.inclusion_tag('teacher/show_list.html')
def show_list(list_data):
    # 一个嵌套标签,实现展示列表数据
    return {'ls': list_data}

继续以teacher应用中学生列表的例子为范例:

先在views里面的student_list_view和student_detail_view里面的学生列表中加入hobby变量,并传入参数列表

def student_list_view(request):
    students = [
        {'id': 1, 'name': 'Adam', 'age': 19, 'sex': 1, 'hobby': ['篮球', '足球', '排球']},
        {'id': 3, 'name': 'Betty', 'age': 19, 'sex': 0, 'hobby': ['羽毛球', '毽子', '乒乓球']},
        {'id': 11, 'name': 'Cathy', 'age': 18, 'sex': 0, 'hobby': ['羽毛球', '毽子', '乒乓球']},
        {'id': 12, 'name': 'Daisy', 'age': 20, 'sex': 0, 'hobby': ['羽毛球', '毽子', '乒乓球']},
        {'id': 15, 'name': 'Ethan', 'age': 19, 'sex': 1, 'hobby': ['篮球', '足球', '排球']},
        {'id': 26, 'name': 'Adda', 'age': 19, 'sex': 0, 'hobby': ['篮球', '网球', '排球']},
        {'id': 27, 'name': 'Bryan', 'age': 20, 'sex': 1, 'hobby': ['篮球', '足球', '排球']},
        {'id': 38, 'name': 'Carmen', 'age': 18, 'sex': 0, 'hobby': ['篮球', '网球', '排球']},
        {'id': 39, 'name': 'Dolphin', 'age': 20, 'sex': 0, 'hobby': ['篮球', '网球', '排球']},
        {'id': 40, 'name': 'Evan', 'age': 19, 'sex': 1, 'hobby': ['篮球', '网球', '排球']},
    ]
def student_detail_view(request, pk):
    students = {
        1: {'id': 1, 'name': 'Adam', 'age': 19, 'sex': 1, 'hobby':['篮球','足球','排球']},
        3: {'id': 3, 'name': 'Betty', 'age': 19, 'sex': 0, 'hobby':['羽毛球','毽子','乒乓球']},
        11: {'id': 11, 'name': 'Cathy', 'age': 18, 'sex': 0, 'hobby':['羽毛球','毽子','乒乓球']},
        12: {'id': 12, 'name': 'Daisy', 'age': 20, 'sex': 0, 'hobby':['羽毛球','毽子','乒乓球']},
        15: {'id': 15, 'name': 'Ethan', 'age': 19, 'sex': 1, 'hobby':['篮球','足球','排球']},
        26: {'id': 26, 'name': 'Adda', 'age': 19, 'sex': 0, 'hobby':['篮球','网球','排球']},
        27: {'id': 27, 'name': 'Bryan', 'age': 20, 'sex': 1, 'hobby':['篮球','足球','排球']},
        38: {'id': 38, 'name': 'Carmen', 'age': 18, 'sex': 0, 'hobby':['篮球','网球','排球']},
        39: {'id': 39, 'name': 'Dolphin', 'age': 20, 'sex': 0, 'hobby':['篮球','网球','排球']},
        40: {'id': 40, 'name': 'Evan', 'age': 19, 'sex': 1, 'hobby':['篮球','网球','排球']},
    }

再回到学生列表模板前端html文件里添加一个表头"爱好",再在单元格td标签中添加ul标签,其中插入for标签,写入for item in student.hobby调用item,并加入带li标签的模板变量item

  <table class="table">
        <thread>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>爱好</th>
            </tr>
        </thread>
        <tbody>
        {% for student in students %}
            <tr {% if student.sex == 0 %} style="background-color: lightpink"{% else %} style="background-color: aqua" {% endif %}>"
                <td><a href="{% url 'teacher:student_detail' student.id %}">{{ student.id }}</a></td>
                <td>{{ student.name }}</td>
                <td>{{ student.age }}</td>
                <td>{{ student.sex|my_male:'en' }}</td>
                <td>
                    <ul>
                        {% for item in student.hobby %}
                            <li>{{ item }}</li>
                            {% endfor %}
                    </ul>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

在学生详情前端html页面新增爱好表头及传参

思考:当我们的模板里有很多数据需要填进去,并且还要设置不同的样式(CSS),有没有其他办法可以让这些数据填入在渲染的时候不用那么麻烦呢?那我们就可以用到包含标签(装饰器)的方法了。

在teacher_tags页面,新增定义

def show_list(list_data):
    '''
    这是一个嵌套标签,实现展示列表数据的功能
    :param list_data:
    :return:
    '''
    return {'ls': list_data}

并在templates目录的teacher目录下新建一个show_list.html的模板前端页面。

在teacher_tags标签页顶部插入以下指令导入get_template模块

from django.template.loader import get_template

在return下方加入以下指令来导入该新建的模板:

t = get_template('teacher/show_list.html')

register.inclusion_tag(show_list)

这里我们可以用一个装饰器来实现同样的功能:

@register.inclusion_tag('teacher/show_list.html')

def show_list(list_data):
    '''
    这是一个嵌套标签,实现展示列表数据的功能
    :param list_data:
    :return:
    '''
    return {'ls': list_data}

这样就可以把
t = get_template('teacher/show_list.html')
register.inclusion_tag(show_list)去掉了。

在新建的show_list.html里写入:

<ul>
    {% for l in ls %}
        <li>{{ l }}</li>
    {% endfor %}
</ul>

那么学生列表页student_list_page前端里关于hobby的td标签就可以缩减为{% show_list student.hobby %}

  <table class="table">
        <thread>
            <tr>
                <th>学号</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>爱好</th>
            </tr>
        </thread>
        <tbody>
        {% for student in students %}
            <tr {% if student.sex == 0 %} style="background-color: lightpink"{% else %} style="background-color: aqua" {% endif %}>"
                <td><a href="{% url 'teacher:student_detail' student.id %}">{{ student.id }}</a></td>
                <td>{{ student.name }}</td>
                <td>{{ student.age }}</td>
                <td>{{ student.sex|my_male:'en' }}</td>
                <td>
                    {% show_list student.hobby %}
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

使用包含标签(装饰器)在学生列表前端html页面插入爱好传参的代码写法
同样,在学生详情页的前端页面,也可以通过包含标签的方法,实现简洁的代码编写。

使用包含标签(装饰器)在学生详情前端html页面插入爱好传参的代码写法

这个show_list.html等于单独拿出来做了一个格式模板,只负责显示格式的功能渲染,这样,当表格的数据项目有很多时,你就不需要去为每一个数据项目再去设置格式那么繁琐了。

引用上下文变量

@register.inclusion_tag('teacher/show_list.html', takes_context=True)

def show_list(context, list_data):
    '''
    这是一个嵌套标签,实现展示列表数据的功能
    :param list_data:
    :return:
    '''
    return {'ls': list_data, 'context': context}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值