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).

我的一个简单代码如下

  1. #!/usr/bin/env python
  2. #coding:utf-8
  3. from django import template
  4. register = template.Library()
  5. def percent_decimal(value):
  6. value = float(str(value))
  7. value = round(value, 3)
  8. value = value * 100
  9. return str(value) + '%'
  10. 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最基本的格式如下

  1. from django import template
  2. register = template.Library()
  3. class TestNode(template.Node):
  4. def __init__(self):
  5. pass
  6. def render(self, context):
  7. return "xxxxx"
  8. def test(parser, token):
  9. return TestNode()
  10. 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的实现机制后。看一个复杂一点点的代码。

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

django 自定义标签和过滤器的更多相关文章

  1. django中自定义标签和过滤器

    想要实现自定义标签和过滤器需要进行准备工作: 准备(必需)工作: 1  在某个app下创建一个名为templatetags(必需,且包名不可变)的包.假设我们在名为polls的app下创建了一个tem ...

  2. python 全栈开发,Day70(模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介)

    昨日内容回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  3. Django 模板 语法 变量 过滤器 模板继承 组件 自定义标签和过滤器 静态文件相关

    本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关于模板渲染你只需要记两种特殊符号(语法 ...

  4. Django基础(2)--模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介

    没整理完 昨日回顾: 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 ...

  5. Django模板自定义标签和过滤器,模板继承(extend),Django的模型层

    上回精彩回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  6. Django框架(七)—— 模板层:变量、过滤器、标签、自定义标签和过滤器

    目录 模板层:变量.过滤器.标签.自定义标签和过滤器 一.模板层变量 1.语法 2.使用 二.模板层之过滤器 1.语法 2.常用过滤器 3.其他过滤器 三.模板值标签 1.for标签 2.if标签 3 ...

  7. day58——模板继承、组件、自定义标签和过滤器、inclusion_tag、静态文件配置、url别名和反向解析、url命名空间

    day58 模板相关 模板继承(母版继承) 1. 创建一个xx.html页面(作为母版,其他页面来继承它使用) 2. 在母版中定义block块(可以定义多个,整个页面任意位置) {% block co ...

  8. Django框架(六)--模板层:变量、过滤器、标签、自定义标签和过滤器

    将页面的设计和Python的代码分离开会更干净简洁更容易维护. 我们可以使用 Django的 模板系统 (Template System)来实现这种模式 # django模板修改的视图函数 def c ...

  9. django自定义模板和过滤器

    -自定义过滤器 -1 先app是不是已经在setting中注册 -2 在app下创建一个templatetags(****名字不能变***)的文件夹(模块) -3 在模块下创建一个py文件,名字随意: ...

随机推荐

  1. Subversion how[Reprint]

    1.   Subversion简介 Subversion(简称SVN)是一款功能强大的开源版本控制工具,支持Linux和Windows平台. SVN可以有两个访问方式,一种是独立服务器直接访问,即利用 ...

  2. 常用的sql函数

    常用的sql函数 concat('hello','world') 结果:helloworld  作用:拼接 substr('helloworld',1,5)      hello           ...

  3. 动画--过渡函数 transition-timing-function

    transition-timing-function属性指的是过渡的“缓动函数”.主要用来指定浏览器的过渡速度,以及过渡期间的操作进展情况,其中要包括以下几种函数: (单击图片可放大) 案例展示: 在 ...

  4. 变形--原点 transform-origin

    任何一个元素都有一个中心点,默认情况之下,其中心点是居于元素X轴和Y轴的50%处.如下图所示: 在没有重置transform-origin改变元素原点位置的情况下,CSS变形进行的旋转.位移.缩放,扭 ...

  5. angular 依赖注入

    依赖注入    依赖注入(DI)是一个经典的设计模式, 主要是用来处理组件如何获得依赖的问题.关于DI,推荐阅读Martin Flower的文章(http://martinfowler.com/art ...

  6. 《C语言入门很简单》欢乐槽点

    p24 在C语言中,有三种基本的数据类型供选择,它们有着不同的精度和广度,可以根据自己的需要选择合适的.这三种数据类型分别是整型.浮点型.字符型,它们可谓是C语言数据的三大变形金刚. p237 评:自 ...

  7. FastJson之有道翻译

    在AndroidMainifast.xml中加入相应的访问权限 <uses-permission android:name="android.permission.INTERNET&q ...

  8. drupal 做301跳转(删除url里的www), 关键代码 可用到任何网站

    //hook_init(); function ex_init(){ //删除 url 前面的 www if (substr($_SERVER['HTTP_HOST'],0,3) == 'www'){ ...

  9. V4L2应用程序框架-二【转】

    本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11371439 V4L2驱动框架 主设备号: 81 次设备号:    0-63    64 ...

  10. CC2541的任务与事件,以及红外捕捉.

    因为红外遥控要占用的系统中断时间可能超过了80ms, 极有可能导致蓝牙断线, 特别是连续两次按键, 100%断线. 后来根据蓝牙技术群里的哥们提示, 觉得不能在一个中断中delay得太久, 只能用任务 ...