django模板中自带了一系列标签,有<if>,<ifequal>,<ifnotequal>,<for>等,但有时也不能满足需求,比方说我要判断一个对象是否在一个集合中,就没有实现这个功能的现成标签。要实现这个功能,有两种方式,一种是自定义过滤器,一种是自定义标签:
自定义过滤器比较简单:
import datetime from django import template from django.template.base import (Node, NodeList, TemplateSyntaxError) register = template.Library() @register.filter(name='authorityfilter') def authorityfilter(value, authority_list): for authority in authority_list: if authority == value: return True return False
使用场景:用户登录的时候判断当前用户的权限,如果是超级管理员,则可以查看所有用户的信息,并添加用户等,如果只是普通的用户,则只能看到自己的信息:
自定义过滤器引用方式:
{% load common_tags %} {% if 'accountsuperuser'|authorityfilter:request.session.authority_list_button %} <li><a href="{% url accounts_index %}" target="navTab" rel="accountindex" title="用户管理">用户管理</a></li> {% else %} <li><a href="{% url accounts_info user.id %}" target="navTab" rel="accountindex" title="用户信息">用户信息</a></li> {% endif %}
自定义标签比较复杂,在这里学到一种学习方法,因为django框架是开源的,所以安装好后直接可以看到它的源码。我想判断一个对象是否在一个集合中,要定义的这个标签跟django自带的<ifequal>这个标签实现的功能很类似,好了,先把这个<ifequal>这个标签的源码找出来研究一下。<ifequal>标签源码如下:
@register.tag def ifequal(parser, token): """ Outputs the contents of the block if the two arguments equal each other. Examples:: {% ifequal user.id comment.user_id %} ... {% endifequal %} {% ifnotequal user.id comment.user_id %} ... {% else %} ... {% endifnotequal %} """ return do_ifequal(parser, token, False) @register.tag def ifnotequal(parser, token): """ Outputs the contents of the block if the two arguments are not equal. See ifequal. """ return do_ifequal(parser, token, True) def do_ifequal(parser, token, negate): bits = list(token.split_contents()) if len(bits) != 3: raise TemplateSyntaxError("%r takes two arguments" % bits[0]) end_tag = 'end' + bits[0] nodelist_true = parser.parse(('else', end_tag)) token = parser.next_token() if token.contents == 'else': nodelist_false = parser.parse((end_tag,)) parser.delete_first_token() else: nodelist_false = NodeList() val1 = parser.compile_filter(bits[1]) val2 = parser.compile_filter(bits[2]) return IfEqualNode(val1, val2, nodelist_true, nodelist_false, negate) class IfEqualNode(Node): child_nodelists = ('nodelist_true', 'nodelist_false') def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): self.var1, self.var2 = var1, var2 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.negate = negate def __repr__(self): return "<IfEqualNode>" def render(self, context): val1 = self.var1.resolve(context, True) val2 = self.var2.resolve(context, True) if (self.negate and val1 != val2) or (not self.negate and val1 == val2): return self.nodelist_true.render(context) return self.nodelist_false.render(context)
改成<ifcontain>标签后,代码如下:
def iscontain(obj, obj_list): for tmpobj in obj_list: if tmpobj == obj: return True return False class IfContainNode(Node): child_nodelists = ('nodelist_true', 'nodelist_false') def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): self.var1, self.var2 = var1, var2 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.negate = negate def __repr__(self): return "<IfContainNode>" def render(self, context): val1 = self.var1.resolve(context, True) val2 = self.var2.resolve(context, True) if (self.negate and not iscontain(val1, val2)) or (not self.negate and iscontain(val1, val2)): return self.nodelist_true.render(context) return self.nodelist_false.render(context) def do_ifcontain(parser, token, negate): bits = list(token.split_contents()) if len(bits) != 3: raise TemplateSyntaxError("%r takes two arguments" % bits[0]) end_tag = 'end' + bits[0] nodelist_true = parser.parse(('else', end_tag)) token = parser.next_token() if token.contents == 'else': nodelist_false = parser.parse((end_tag,)) parser.delete_first_token() else: nodelist_false = NodeList() val1 = parser.compile_filter(bits[1]) val2 = parser.compile_filter(bits[2]) return IfContainNode(val1, val2, nodelist_true, nodelist_false, negate) @register.tag def ifcontain(parser, token): """ Outputs the contents of the block if the second argument contain the first argument. Examples:: {% ifcontain user userlist %} ... {% endifcontain %} {% ifnotcontain user userlist %} ... {% else %} ... {% endifnotcontain %} """ return do_ifcontain(parser, token, False) @register.tag def ifnotcontain(parser, token): """ Outputs the contents of the block if the second argument not contain the first argument. See ifcontain. """ return do_ifcontain(parser, token, True)
引用方式:
{% load common_tags %} {% ifcontain 'accountsuperuser' request.session.authority_list_button %} <li><a href="{% url accounts_index %}" target="navTab" rel="accountindex" title="用户管理">用户管理</a></li> {% else %} <li><a href="{% url accounts_info user.id %}" target="navTab" rel="accountindex" title="用户信息">用户信息</a></li> {% endifcontain %}
好了,大功告成!