zoukankan      html  css  js  c++  java
  • django 自定义标签和过滤器

    django 自定义标签和过滤器

     Django支持自定义标签和过滤器。起初还不太重视它这项功能,但最近试了试自定义标签。发现django这个功能实在是太爽了。

    首先在你项目的一个app中建立一个python源文件夹,(即文件夹里面要包含一个__init__.py.)文件夹名为templatetags.  此文件夹便是存放自定义标签和过滤器的源码的地方了。

    再如果是在templatetags文件夹中定义了标签,如 test_tags.py,要如何使用我们自定义的test_tags.py呢。很简单,只要在django的模板中加入{% load test_tags %},在test_tags.py 源文件中的自定义标签就可以在有load语句的模板中使用了。

    下面详细的来谈谈建立自定义标签的过程以及方法。

    1.建立项目,app的不说。只要在随意一个app中建立上文提到的templatetags文件夹。

    这里是有点不理解的地方,在任意一个app建立的tags别的app能够使用吗?起初对此很疑惑。以为在一个app下建立的tags就这一个app能使用。为了大家都能够使用自己定义的tags,我还想把templatetags单独拿出来,跟普通app在项目当中是平级地位。这种思路搞了很久发现行不通。无奈只好打算使用copy在每一个app都复制一份templatetags。(当然这只是我起初的错误想法)但后来发现,居然一个app中有,其他的app中就可以直接使用此自定义的文件了。只需要在需要的模板当中(不管模板是在你的那个app中)调用load语句将自定义的文件load进来便可以。

    随后看了看一些文档,只要templatetags所在位置是settings.py中INSTALLED_APPS中配置过的,或是在TEMPLATE_DIRS配置过的,任意一个位置便可以。

    一定记得要在templatetags文件夹中包含__init__.py文件。空文件便可。

    2.编写自定义文件代码test_tags.py。

    现看看简单一点的过滤器(filter).

    我的一个简单代码如下

    Python代码  收藏代码
    1. #!/usr/bin/env python  
    2. #coding:utf-8  
    3.   
    4. from django import template  
    5.   
    6. register = template.Library()  
    7.   
    8. def percent_decimal(value):  
    9.       
    10.     value = float(str(value))  
    11.     value = round(value, 3)  
    12.     value = value * 100  
    13.       
    14.     return str(value) + '%'  
    15. register.filter('percent_decimal', percent_decimal)   

    以上代码的意思是将传过来的小数转换成百分比显示。(django自带一个widthratio标签页可以完成此问题,但它的误差太大,小数位直接截掉了)。

    其中register = template.Library(),register.filter('percent_decimal', percent_decimal) 两句是将所写代码注册到能用标签。最后一句的register.filter('percent_decimal', percent_decimal) 。第一个参数是字符串,就只在模板中使用时候的字符串比如{{12.09|percent_decimal}},名字可以自由取得。后面一个参数接受一个函数名,这个便是上面自定义的percent_decimal方法了。此方法中的value参数便是从模板中传递过来的参数。比如{{12.09|percent_decimal}}, percent_decimal方法接受到的value参数便是
    12.09.

    再来看看如何自定义tags。

    自定义tags相对自定义filter要复杂一点。但仔细研究的话难度也不大。

    自定义tags最基本的格式如下

    Python代码  收藏代码
    1. from django import template  
    2.   
    3. register = template.Library()  
    4.   
    5. class TestNode(template.Node):  
    6.     def __init__(self):  
    7.         pass  
    8.   
    9.     def render(self, context):  
    10.         return "xxxxx"  
    11.   
    12. def test(parser, token):  
    13.     return TestNode()  
    14.   
    15. register.tag('my_tag', test)  

     其中包的引入和注册跟filter类型。主要的功能代码是一个类(继承自template.Node,所有的自定义tags都必须从这个类继承)和一个方法,以上代码什么功能都没有做,但我们要先搞明白它的实现机制。

    如果从模板中使用以上的自定义tags,比如{% my_tag aaa.bbb %},则会调用上面代码注册的test方法,其中test方法中有两个参数,一个是parser,这个作用是挺大的,稍后说明。另一个是token,这个便是从模板当中使用的这个标签中所包含的所有字符串。如果使用的是{{ my_tag aaa.bbb }}则,token的值为“my_tag aaa.bbb”。注意是字符串类型。

    随后调用TestNode类,当中有个render方法,其中有个参数是context,这个context参数就是在执行模板的渲染时由 View 传入的,在这里跟在被渲染的模板中可以调用同样的变量,可以试验在render中打印 "print user",便显示的是登陆用户的信息。

    大概明白了自定义tags的实现机制后。看一个复杂一点点的代码。

    Python代码  收藏代码
    1. class PermissionLevel(template.Node):  
    2.       
    3.     """ 
    4.     根据级别返回相应值 
    5.     """      
    6.       
    7.     def __init__(self, sequence, text_level):  
    8.         self.sequence = sequence  
    9.         self.text_level = text_level  
    10.         pass  
    11.     def render(self, context):  
    12.         userInfo = context['user']  
    13.         level = 4  #拿到用户级别  
    14.           
    15.         values = self.sequence.resolve(context, True)  
    16.         if self.text_level <= level:  
    17.             return str(values)  
    18.         else:  
    19.              return 'xxx'  
    20.   
    21. def do_permission_level(parser, token):  
    22.           
    23.     try:  
    24.         tag_name, text_name, text_level = token.split_contents()  
    25.     except:  
    26.         raise template.TemplateSyntaxError,   
    27.                    "%r 标签语法错误,后面参数为两位,分别为变量名和该变量信息隐私等级" %   
    28.                     token.split_contents[0]  
    29.     try:  
    30.         text_level = int(text_level)  
    31.     except:  
    32.         raise TemplateSyntaxError, "permission_level标签语法错误,信息隐私等级应为整型数字"  
    33.     sequence = parser.compile_filter(text_name)  
    34.       
    35.     return PermissionLevel(sequence, text_level)  
    36.        
    37. register.tag('permission_level', do_permission_level)  

    以上的代码完成的功能是判定一个信息的隐私级别,再根据登陆用户的权限来区分显示或不显示。在模板中的用法如下

    {% permission_level  objects.count  4 %}

    其中permission_level  为标签名,objects.count是从view中传递过来的变量或属性。后面的 4 便是此属性(objects.count)的隐私级别为4,只有登录用户隐私级别大于它的时候才会显示,否则显示为“xxx”。

    下面仔细来分析一下上面的代码。

    tag_name, text_name, text_level = token.split_contents()
    这一句将{% permission_level  objects.count  4 %}分解成三个字符,其中text_name为“objects.count ”。这里跟自定义的filter不同,filter 是可以接受非字符的参数的,类型{{ 0.123|floatformat:2 }}也可以是{{ 0.123|floatformat:“2” }},后面的2参数加了引号。其中如果不加引号的话便传递的是非字符对象,像模板中的user是可以通过filter传递过去的。但tags不同,tag传递给注册的函数中的参数是字符串。

    当时想到做自定义的tags也是项目需要。但自己开始做的时候发现tag传递的是字符串,当时也查了不少资料没找到解决的方法,那时就想放弃自定义tags了。但注意到django自带的tags不也是传递字符吗,像{%if user%}, {% for item in test_list %}这样的,django肯定有什么方法可以将类似“user”, "test_list"这样的字符和view中传递来的对象关联起来。于是便开始硬着头皮看django的源码了。(要知道对于像我这样的菜鸟来说。看源码可不是容易的事情)。

    到底django是用什么魔法做到字符变对象的呢。起先我以为是这样的,比如{% if user  %},则先提取user取来,再将传递过去的user从context中取去,user=context['user'],但后来一想,单个的对象好想是可以,但如果有句点符号的是怎么做到的呢。就像user.username?难道是再将它通过字符串操作再分离一次,但如果遇到多个句点符号呢?类似

    user.profile.realname。照这个思路看源码,发现不是我想的这样的。有些源代码没看太懂,但正是这些没看懂的代码才是关键。

    再回头看看上面的代码,注册标签的代码方法中有个parser参数,正是这个参数。

    对照上面的代码。

    sequence = parser.compile_filter(text_name)
    将开始从token.split_contents()中分离出来的 像:user,,user.age ,  user.profile.realname等字符串先编译成一个sequence 对象。怎么编译的我也不太明白,不去管它了。

    随后在类方法里面有句values = self.sequence.resolve(context, True)
    再打印出values来看看,type(values)看看,哈哈。不再是字符串了,是真正的实例对象或是变量。

    那么一切OK。虽然不知道Django中这两句是怎么样实现的,但不管了。至少现在我们可以自由的定制适合的filter和tags了。

  • 相关阅读:
    WMware 10 Ubuntu 12.04 进入Unity模式
    Spring+Struts集成(第二种方案)
    strut1.X和spring整合的二种方法
    Struts+Spring+Hibernate的Web应用执行过程
    Hibernate配置文件中配置各种数据库的driver、URL
    连接Oracle数据库的Hibernate配置文件
    Hibernate SQL 方言(hibernate.dialect)
    HibernateUtil.java
    hibernate里的generator中class =value介绍
    Hibernate的generator属性
  • 原文地址:https://www.cnblogs.com/wt869054461/p/4062341.html
Copyright © 2011-2022 走看看