精华内容
下载资源
问答
  • 主要介绍了django自定义模板标签过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • django自定义模板标签

    2019-03-20 21:44:00
    # 创建自定义模板标签目录 django_project_name  app_name  templatetags (创建Python Packge,注意一定要用templatetags这个名字)  my_tags.py(名字随便起) # my_tags.py里面的内容 *先导入模块 from ...

    # 创建自定义模板标签目录

    django_project_name

        app_name

           templatetags (创建Python Packge,注意一定要用templatetags这个名字)

             my_tags.py(名字随便起)

     

    # my_tags.py里面的内容

     *先导入模块

    from django import template

    register = template.Library()

     

    @register.simple_tag() # simple_tag能够对传入多个参数有效

    @register.filter # filter只能对一个参数传入有效,调用到时候这样用 {{ xx.line | ljf_power}}

    @register.inclusion_tag('xxx.html')  

    def XXX(需要传入的参数):

       """

      里面写自定义的方法

       """

      return

     

    # xxx.html里面内容

    ...........

    此处省略,写入自己需求的代码

    ...........

     

    # 母版

    {%load my_tags%}

     {%XXX 方法里传入的参数%}

    转载于:https://www.cnblogs.com/274831730wang/p/10567953.html

    展开全文
  • django自定义模板标签(tag)

    需求:在前端页面中,需要对一个数值做运算,运算后需要保留两位小数点,但是django的模板中很难做到这个,此时,可以通过自定义tag来实现这个功能。
    1、首先在app下新建一个目录templatetags(目录名称固定):
    2、新建一个py文件,名称可根据需要自定义命名,同时,需要在该目录下新建一个空白文件__init__.py:

    # 我这里的目录是:项目/app/templatetags/templatehelper.py
    from django import template
    register = template.Library()
    
    @register.filter(name="percent")
    def percent(value):
        '''
        传入一个num,然后做运算,保留小数点两位
        '''
        return '{:.2%}'.format(float(value)/100*100)
    
    

    3、需要在项目的settings.py文件中添加该模块

    INSTALLED_APPS = [
    	......
        'app.templatetags',
       	......
    
    ]
    

    4、在模板中应用该标签
    首先在文件的头部load这个标签,在应用percent这个函数

    {% load templatehelper %}
    {{ number |percent}}
    
    展开全文
  • 主要介绍了浅谈Django自定义模板标签template_tags的用处,具有一定借鉴价值,需要的朋友可以参考下。
  • Django自定义模板标签和过滤器 1.创建模板库 在某个APP所在目录下新建包templatetags,然后在其中创建存储标签或者过滤器的的模块,名称随意,例如myfilters.py。 在这个模块中编写相关代码。 注意:...

    1.创建模板库

    在某个APP所在目录下新建包templatetags,然后在其中创建存储标签或者过滤器的的模块,名称随意,例如myfilters.py

    在这个模块中编写相关代码。

    注意:templatetags所在APP应该在配置文件中进行配置。

    2.定义过滤器

    过滤器是一个函数,第一个参数是被处理的值,之后,可以有任意个参数,作为过滤器参数。

    from django import template
    from django.template.defaultfilters import stringfilter
    
    register=template.Library()
    
    # 去除指定字符串
    @register.filter(name='mycut')
    @stringfilter
    def mycut(value,arg):
        return value.replace(arg,'')
    
    # 注册过滤器
    # register.filter(name='mycut',filter_func=mycut)

    3.定义标签

    • simple_tag

      处理数据,并返回具体数据

      @register.simple_tag(name='posts_count')
      def total_posts():
          return Post.published.count()
    • inclusion_tag

      处理数据,并返回一个渲染的模板

      @register.inclusion_tag('blog/post/latest.html')
      def show_latest_posts(count=5):
          latest_posts=Post.published.order_by('-publish')[:5]
          return {
              'latest_posts':latest_posts,
          }

      blog/post/latest.html内容如下:

      <strong>最新文章</strong>
      <ul>
      {% for post in latest_posts %}
      <li>
          <a href="{% url 'blog:post_detail' post_id=post.id %}">{{ post.title }}</a>
      </li>
      {% endfor %}
      </ul>

    4.使用

    使用自定义的标签或过滤器之前,在模板文件中,需要使用 {% load 模块名称 %} 加载自定义的标签和过滤器。

    之后,就可以向使用Django自带的标签一样使用了。

    注意:即使当前模板继承的基模板中已经load了自定义标签或过滤器所在的模块,在当前模板中,依然需要再次load。

    posted on 2019-03-31 16:55 老夫不喝鸡汤 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/erxiaozi/p/10632031.html

    展开全文
  • django 自定义模板标签和过滤器

    千次阅读 2016-11-23 17:23:46
    django 自定义模板标签和过滤器   1.创建一个模板库 使用模板过滤器的时候,直接把过滤器写在app里, 例如:在app里新建一个templatetags的文件夹,这个目录应当和 models.py 、 views.py 等处于同一层次。例如...

     

    django 自定义模板标签和过滤器

     

    1.创建一个模板库

    使用模板过滤器的时候,直接把过滤器写在app里,

    例如:在app里新建一个templatetags的文件夹,这个目录应当和 models.py 、 views.py 等处于同一层次。例如:

    books/

       __init__.py

       models.py

       templatetags/

       views.py

    在 templatetags 中创建两个空文件:一个 __init__.py (告诉Python这是一个包含了Python代码的包)和一个用来存放你自定义的标签/过滤器定义的文件。第二个文件的名字稍后将用来加载标签。例如,如果你的自定义标签/过滤器在一个叫作 poll_extras.py 的文件中,你需要在模板中写入如下内容: {% load poll_extras %}

    {% load %} 标签检查 INSTALLED_APPS 中的设置,仅允许加载已安装的Django应用程序中的模板库。

    要成为有效的标签库,模块必须包含一个模块级的变量: register ,这是一个 template.Library 的实例。这个 template.Library 实例是包含所有已注册的标签及过滤器的数据结构。因此,在模块的顶部位置插入下述代码:

    from django import template

    register = template.Library()

    2. 自定义模板过滤器

    自定义过滤器就是有一个或两个参数的Python函数::

    例如,在过滤器 {{ var|foo:”bar” }} 中,过滤器 foo 会被传入变量 var 和参数 bar 的内容。

    过滤器函数应该总有返回值,而且不能触发异常,它们都应该静静的失败。如果有一个错误发生,它们要么返回原始的输入字符串,要么返回空的字符串,无论哪个都可以。

    1)这里是一些定义过滤器的例子:

    def cut(value, arg):

       "Removes all values of arg from the given string"

    return value.replace(arg, '')

    def lower(value): # Only one argument.

       "Converts a string into all lowercase"

       return value.lower()

    2)这里是一些如何使用过滤器的例子:

       {{ somevariable|cut:”0″ }}

    3)下面是一个完整的模板库的例子,提供了一个cut 过滤器:

    from django import template

    register = template.Library()

    @register.filter(name='cut') (装饰器)

    def cut(value, arg):

       return value.replace(arg, '')

     

    @register.filter

    def lower(value):

       return value.lower()

       注意:1)在定义过滤器时,需要用Library 实例来注册它,这样就能通过Django的模板语言来使用了: Python 2.4或更新,可以通过上面的装饰器   实现,如果不使用 name参数,@register.filter那么Django将会使用函数名作为过滤器的名字

    2)保证templatetags在已经INSTALLED_APPS里面

     

     

    编写自定义模板标签

    标签比过滤器复杂的多,因为标签可以做任何事情。

    快速回顾

    模板系统工作有两个流程:编译和渲染。去定义一个模板标签,你需要知道如何去编译和如何去渲染。当django编译一个模板的时候,它会把原始的模板文本分割成一个个节点,每个节点都是django.template.Node实例并且有一个render()方法。一个编译好的模板是一个Node对象的列表。当你在一个已经编译好的模板对象调用render方法时,模板会对node列表中的每一个Node调用render方法(使用给定的上下文),结果会被级联在一起去组成模板的输出。因此,定义一个模板标签,你需要知道一个原始的模板标签是如何被转换成一个Node,以及这个node的render方法要做什么。

    编写编译函数

    模板解析器每遇到一个模板标签,它会和标签内容和解析器对象本省一起去调用一个python函数,这个函数应该返回一个基于标签内容的Node实例。举个例子,让我们写一个标签{% current_time %},这个标签会展示当前的日期时间,格式根据参数来决定,参数格式都是strftime()的。首先决定一个标签的语法是很重要的,在我们的例子中,这个标签大概是这样的:

    <p>The time is {% current_time"%Y-%m-%d %I:%M %p" %}.</p>

     

    这个函数的解析器应该获取到这些参数并且创建一个Node对象

     

     

    from django import template

    def do_current_time(parser, token):

       try:

           # split_contents() knows not to split quoted strings.

           tag_name, format_string = token.split_contents()

       except ValueError:

           raise template.TemplateSyntaxError("%r tag requires a singleargument" % token.contents.split()[0])

       if not (format_string[0] == format_string[-1] and format_string[0] in('"', "'")):

           raise template.TemplateSyntaxError("%r tag's argument should be inquotes" % tag_name)

       return CurrentTimeNode(format_string[1:-1])

     

     

    tips:

      ● parser是模板解析器对象

      ● token.contents是标签的原始内容,在我们的例子中时'current_time "%Y-%m-%d %I:%M %p"'

      ●token.split_contents()方法把参数按空格分开,同时保留引号之间的内容,如果使用token.contents.split()的话,这个函数会将所有空格都分开,所以建议还是使用token.split_contents()

      ● 这个函数会引发django.template.TemplateSymtaxError,并附有有用的信息

      ● TemplateSyntaxError异常使用tag_name变量,所以不要在你的错误信息里面硬编码标签名,因为token.contents.spilt()[0]永远是你的标签名

      ● 这个函数返回一个包括所有有关这个标签的内容的CurrentTimeNode对象,所以你只需把参数穿进去就可以了

      ● 这个解析过程是非常底层的,所以直接用就好了,因为底层所以快速。

    编写渲染器

    编写自定义标签的第二步是定义一个Node的子类并且定义一个render方法

     

     

    from django import template

    import datetime

    class CurrentTimeNode(template.Node):

       def __init__(self, format_string):

           self.format_string = format_string

       def render(self, context):

           return datetime.datetime.now().strftime(self.format_string)

     

     

     

    tips:

      ● __init__()从上面的do_current_time()中获取format_string,记得只通过__init__()函数传参

      ● render()方法才是真正做事情的

      ● render函数不会抛出任何异常,只会默默的失败(如果发生异常的话)

    最终,编译和渲染的非耦合组成了一个有效的模板系统,因为一个模板可以渲染多个上下文而不用多次解析。

    自动转义注意事项

    模板标签的输出并不会自动的执行自动转义过滤器的,所以当你编写一个模板标签的时候你需要注意这些事情:

    如果render函数在一个上下文变量里面存储结果(而不是一个字符串),你需要注意正确的使用mark_safe(),当该变量已经是最终渲染了,你需要给它打上标识,以防会受到自动转义的影响。

    并且,你的模板标签新建一个用于进一步渲染的上下文,记得把自动转义属性设置为当前上下文的值。Context的 __init__()方法接受一个autoescape的参数

    def render(self, context):

        #...

       new_context = Context({'var': obj}, autoescape=context.autoescape)

        #... Do something with new_context ...

     

    这不是一个很常用的情景,但是当你自己渲染一个模板的时候会很有用

    def render(self, context):

        t= template.loader.get_template('small_fragment.html')

       return t.render(Context({'var': obj}, autoescape=context.autoescape))

     

    如果我们不传这个参数的时候,结果可能是永远都是自动转义的,即使这个标签实在{% autoescape off %}块里面。

    线程安全考虑

     一旦一个节点被解析,render方法会被调用任意次,由于django有时运行在多线程的环境,单个节点可能会被两个独立的请求的不同上下文同时渲染,因此,保证你的模板标签线程安全是很重要的

    为了保证你的模板标签是线程安全的,你应该永远不要存储信息在节点本身。举个例子,django提供一个内建的cycle模板标签,这个标签每次渲染的时候都会循环一个给定字符串的列表

    {% for o in some_list %}

       <tr class="{% cycle 'row1' 'row2' %}>

           ...

       </tr>

    {% endfor %}

     

    一个朴素的CycleNode的实现可能想这样:

    class CycleNode(Node):

       def __init__(self, cyclevars):

           self.cycle_iter = itertools.cycle(cyclevars)

       def render(self, context):

           return self.cycle_iter.next()

     

    但,假设我们有两个模板,同时渲染上面那个小模板:

      ● 线程1执行第一次循环迭代,CycleNode.render()返回row1

      ● 线程2执行第一次循环迭代,CycleNode.render()返回row2

      ● 线程1执行第二次循环迭代,CycleNode.render()返回row1

      ● 线程2执行第二次循环迭代,CycleNode.render()返回row2

    CycleNode是可以迭代的,但却是全局迭代,由于线程1和线程2是关联的,所以它们总是返回相同的值,显然这不是我们想要的结果。

    解决这个问题,django提供了一个正在被渲染的模板的上下文关联的render_context,这个render_context就像一个python字典一样,并且应该在render方法被调用之间保存Node状态

    让我们使用render_context重新实现CycleNode吧

     

     

    class CycleNode(Node):

       def __init__(self, cyclevars):

           self.cyclevars = cyclevars

       def render(self, context):

           if self not in context.render_context:

               context.render_context[self] = itertools.cycle(self.cyclevars)

           cycle_iter = context.render_context[self]

           return cycle_iter.next()

     

     

     

    注册标签

    和过滤器注册差不多

     

     

    register.tag('current_time',do_current_time)

     

    @register.tag(name="current_time")

    def do_current_time(parser, token):

       ...

     

    @register.tag

    def shout(parser, token):

       ...

     

    给标签传模板变量

    尽管你可以是用token.split_contents()传入任意个参数,但考虑一个参数是一个模板变量的情况(这是一个动态的情况)

    假如我们有一个这样的标签,接受一个给定的日期和指定格式,返回用指定格式格式化的日期,像这样:

    <p>This post was last updated at {%format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>

     

    现在你的解析器大概是这样的

     

    from django import template

    def do_format_time(parser, token):

       try:

           # split_contents() knows not to split quoted strings.

           tag_name, date_to_be_formatted, format_string = token.split_contents()

       except ValueError:

           raise template.TemplateSyntaxError("%r tag requires exactly two arguments"% token.contents.split()[0])

       if not (format_string[0] == format_string[-1] and format_string[0] in('"', "'")):

           raise template.TemplateSyntaxError("%r tag's argument should be inquotes" % tag_name)

       return FormatTimeNode(date_to_be_formatted, format_string[1:-1])

     

    然后FormatTimeNode大概就要这样子了

     

    class FormatTimeNode(template.Node):

       def __init__(self, date_to_be_formatted, format_string):

           self.date_to_be_formatted = template.Variable(date_to_be_formatted)

           self.format_string = format_string

     

       def render(self, context):

           try:

               actual_date = self.date_to_be_formatted.resolve(context)

               return actual_date.strftime(self.format_string)

           except template.VariableDoesNotExist:

               return ''

     

     

    简单的标签

    很多的标签接受很多的参数-字符串或者模板变量-返回一个字符串或者空串,为了减轻这类简单的标签的创建,django提供了一个简单有效的函数simple_tag。这个函数,是django.template.Library的一个方法,接受一个 可以接受任意个参数的函数 ,然后把这个函数包装成一个render函数,以及其他必要的注册等步奏。

    比如之前的current_time函数我们这里可以这样写

     

    ef current_time(format_string):

       return datetime.datetime.now().strftime(format_string)

     

    register.simple_tag(current_time)

    #或者这样

    @register.simple_tag

    def current_time(format_string):

       ...

     

    如果你的模板标签需要访问当前上下文的话,你可以使用takes_context参数,像下面这样:

     

    # The first argument *must* be called"context" here.

    def current_time(context, format_string):

       timezone = context['timezone']

       return your_get_current_time_method(timezone, format_string)

     

    register.simple_tag(takes_context=True)(current_time)

    #或者这样

    @register.simple_tag(takes_context=True)

    def current_time(context, format_string):

       timezone = context['timezone']

       return your_get_current_time_method(timezone, format_string)

     

    或者你想重命名你的标签,你可以这样来指定

    register.simple_tag(lambda x: x - 1,name='minusone')

    #或者这样

    @register.simple_tag(name='minustwo')

    def some_function(value):

       return value - 2

     

    simple_tag还可以接受关键字参数

    @register.simple_tag

    def my_tag(a, b, *args, **kwargs):

       warning = kwargs['warning']

       profile = kwargs['profile']

       ...

       return ...

    {% my_tag 123 "abcd" book.title warning=message|lowerprofile=user.profile %}

    包含标签

    另外一类标签是通过渲染其他的模板来展示内容的,这类标签的用途在于一些相似的内容的展示,并且返回的内容是渲染其他模板得到的内容,这类标签称为“包含标签”。最好我们通过一个例子来阐述。

    我们即将写一个标签,这个标签将输出给定Poll对象的选择的列表,我们可以这样使用这个标签

    {% show_results poll %}

     

    输出大概是这样的

    <ul>

     <li>First choice</li>

     <li>Second choice</li>

     <li>Third choice</li>

    </ul>

     

    下面我们看看怎么实现吧。首先定义一个接受一个poll参数的函数,这个函数返回该poll对象的choices

    def show_results(poll):

       choices = poll.choice_set.all()

       return {'choices': choices}

     

     

    然后我们创建一个要被渲染的模板用于输出

    <ul>

    {% for choice in choices %}

       <li> {{ choice }} </li>

    {% endfor %}

    </ul>

     

    最后是使用inclusion_tag函数注册

    register.inclusion_tag('results.html')(show_results)

    #或者这样

    @register.inclusion_tag('results.html')

    def show_results(poll):

       ...

     

    如果你要使用上下文的话,可以使用takes_context参数,如果你使用了takes_context,这个标签是没有必须参数,不过底层的python函数需要接受一个context的首参(第一个参数必须为context)

     

    #第一个参数必须为context

    def jump_link(context):

       return {

           'link': context['home_link'],

           'title': context['home_title'],

        }

    # Register the custom tag as an inclusiontag with takes_context=True.

    register.inclusion_tag('link.html',takes_context=True)(jump_link)

     

    link.html可以是这样的

    Jump directly to <a href="{{ link}}">{{ title }}</a>.

     

    那么你可以这样来使用这个标签,不需要带任何的参数

    {% jump_link %}

     

    和simple_tag一样,inclusion_tag可以接受关键字参数

    在上下文中设置变量

    到现在为止,所有的模板标签只是输出一个值,现在我们考虑一下给标签设置变量吧,这样,模板的作者可以重用这些你的标签产生的值。

    想要在上下文中设置变量,只需要在render方法中给context对象像字典那样复制,这里有一个升级版的CurrentTimeNode,设置了一个模板变量current_time而不是直接输出该值

    class CurrentTimeNode2(template.Node):

       def __init__(self, format_string):

           self.format_string = format_string

       def render(self, context):

           context['current_time'] =datetime.datetime.now().strftime(self.format_string)

           return ''

     

    注意到这个标签是返回一个空串,使用如下:

    {% current_time "%Y-%M-%d %I:%M%p" %}<p>The time is {{ current_time }}.</p>

     

    注意事项:

    作用范围:上下文中的模板变量仅仅在当前块代码中生效(如果有多个层次的块的话),这是为了预防块之间的变量冲突

    覆盖问题:由于变量名是硬编码的,所有同名的变量都会被覆盖,所以强烈建议使用别名as,但是要使用as的话,编译函数和结点类都要重新定义如下

    {% current_time "%Y-%M-%d %I:%M%p" as my_current_time %}

    <p>The current time is {{my_current_time }}.</p>

     

    class CurrentTimeNode3(template.Node):

       def __init__(self, format_string, var_name):

           self.format_string = format_string

           self.var_name = var_name

       def render(self, context):

           context[self.var_name] = datetime.datetime.now().strftime(self.format_string)

           return ''

     

    import re

    def do_current_time(parser, token):

        #This version uses a regular expression to parse tag contents.

       try:

           # Splitting by None == splitting by spaces.

           tag_name, arg = token.contents.split(None, 1)

       except ValueError:

           raise template.TemplateSyntaxError("%r tag requires arguments"% token.contents.split()[0])

        m= re.search(r'(.*?) as (\w+)', arg)

       if not m:

           raise template.TemplateSyntaxError("%r tag had invalidarguments" % tag_name)

       format_string, var_name = m.groups()

       if not (format_string[0] == format_string[-1] and format_string[0] in('"', "'")):

           raise template.TemplateSyntaxError("%r tag's argument should be inquotes" % tag_name)

       return CurrentTimeNode3(format_string[1:-1], var_name)

     

    赋值标签

    上面的设置一个变量是不是有点麻烦呢?于是django提供了一个有用的函数assignment_tag,这个函数和simple_tag一样,不同之处是这个函数返回的不是一个值,而是一个变量名而已

    成对标签(解析直到遇到块标签)

    目前我们自定义的标签都是单个标签,其实标签可以串联使用,例如标准的{% comment %}会配合{% endcomment %}使用,要编写这样的标签,请使用parser.parse()

    这是一个简化的{% comment %}标签的实现:

    def do_comment(parser, token):

       nodelist = parser.parse(('endcomment',))

       parser.delete_first_token()

       return CommentNode()

     

    class CommentNode(template.Node):

       def render(self, context):

           return ''

     

    parser.parse()接受一个元组的块标签,返回一个django.template.NodeList的实例,这是实例是一个Node对象的列表,包含 解析器在碰到 元组里任何一个块标签之前 碰到的所有的Node对象。比如

    nodelist = parser.parse(('endcomment',))会返回{% comment%}和{% endcomment %}标签之间的所有节点,不包含{% comment %}和{% endcomment %}

    在parser.parse()被调用之后,解析器还没有解析{% endcomment %},所以需要调用parser.delete_first_token()

    由于comment成对标签不必返回任何内容,所以CommentNode.render()仅仅返回一个空串

    如果你的成对标签需要返回内容,可以参考下面这个例子,我们以{% upper %}为例子:

    {% upper %}This will appear in uppercase,{{ your_name }}.{% endupper %}

     

    def do_upper(parser, token):

       nodelist = parser.parse(('endupper',))

       parser.delete_first_token()

       return UpperNode(nodelist)

     

    class UpperNode(template.Node):

       def __init__(self, nodelist):

           self.nodelist = nodelist

       def render(self, context):

           output = self.nodelist.render(context)

           return output.upper()

     

    如果还想了解更多的复杂的例子,你可以去看一下djang/template/defaulttags.py里面的内容,看看{% if %}{%endif %}这些标签是怎么实现的

    展开全文
  • 创建自定义模板标签(template tags) Django提供了以下帮助函数(functions)来允许你以一种简单的方式创建自己的模板标签(template tags): simple_tag:处理数据并返回一个字符串(string) inclusion_...
  • 想要实现自定义标签和过滤器需要进行准备工作: 准备(必需)工作: 1在某个app下创建一个名为templatetags(必需,且包名不可变)的包。假设我们在名为polls的app下创建了一个templatetags的包,并在该包下创建了一个...
  • Django为我们提供了自定义的机制,可以通过使用Python代码,自定义标签和过滤器来扩展模板引擎,然后使用{% load %}标签。 一、前置步骤 Django对于自定义标签和过滤器是有前置要求的,首先一条就是代码布局和文件...
  • 常用内置标签标签 描述 ...{% for %} {% endfor %} ...生成csrf_token标签,用于防护跨站请求伪造攻击 ...加载导入django标签库 {% static %} 加载读取静态资源文件 {% extends xxx %} 使当前模板继承xxx模板
  • 在APPchart 中新建一个文件夹,和两个文件,...mytags.py文件中自定义函数 from django import template register = template.Library() @register.filter def startswith(value, start): """ ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,800
精华内容 3,520
热门标签
关键字:

django自定义模板标签