学习Django中的自定义模板标签和过滤器

263 阅读6分钟

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

在本教程中,我们将看看如何在Django中创建自定义模板标签和过滤器。

Django模板语言带有内置的模板标签,如{% if %} ,以及过滤器,如safe 。然而,你可能会发现你需要Django默认没有包含的功能。在这种情况下,你可以使用Python创建过滤器和标签,并使用load 标签来利用它们。

让我们开始吧!

前提条件

要跟上进度,你必须具备以下条件

  • 有能力创建一个简单的Django应用程序。
  • 安装了Python和Django。
  • 一个合适的IDE,如Pycharm、VS Code等。

目标

在本教程结束时,你将能够。

  • 理解自定义模板标签和过滤器的使用,以及它们如何工作。
  • 创建你的自定义模板标签和过滤器以满足你的需求。

开始学习

你的自定义标签和过滤器必须在一个Django应用程序中。如果你想让你的标签和过滤器在整个项目中使用,你可以创建一个应用来完成这个任务。

按照下面的步骤来创建本教程所需的文件。

  1. 创建一个名为Contacts 的应用程序,并将其添加到你的INSTALLED_APPS
  2. 在你的应用程序中,创建一个叫做templatetags 的目录,与视图、模型等处于同一级别。
  3. 通过创建一个__init__.py 文件使templatetags 目录成为一个 Python 包。
  4. 创建另一个文件custom_tags.py 来保存你的自定义标签和过滤器。

现在你的应用程序的结构将类似于这样。

.Contact
├── contact
│   ├── admin.py
│   ├── apps.py
│   |
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── templatetags
│   │  └── custom_tags.py
│   ├── tests.py
│   ├── url.py
│   └── views.py
├── Contact
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
└──  manage.py

你可以在templatetags 文件夹中创建尽可能多的模块。然而,你应该注意,使用{% load %} 标签只对特定的模块有效,而不是应用。

为了让我们能够加载我们的自定义模板标签和过滤器,我们需要创建一个Library 实例来在Django模板中注册它们。我们将添加以下几行代码来做到这一点。

from django import template
register = template.Library()

为了加载标签和过滤器,我们将在我们的模板中做以下工作。

{% load custom_tags %}

编写自定义过滤器

过滤器通常被写成{{value|filter}}{{value|filter:'arg'}} 。这意味着过滤器在作用于一个值时将会或不会接受一个参数。

考虑一个简单的联系人列表程序,显示联系人和他们的创建时间。

models.py 看起来如下。

from django.db import models

class Contact(models.Model):
    name = models.CharField(max_length=50)
    date = models.DateField()

该应用程序看起来如下,只需做一点样式设计。

Initial Contacts Page

现在让我们创建两个简单的过滤器,将给定名称中的所有字符串、单词的第一个字符大写,同时设置一个颜色。

我们使用@register ,在Django中注册我们的过滤器并给它一个名字。我们的函数需要一个名字作为它的值。

为了使用我们的过滤器,我们在模板中使用行{% load custom_tags %}

template_tags/custom_tags.py

# create the register instance by initializing it with the Library instance.
from django import template

register = template.Library()

# An upper function that capitalizes word passed to it. We then register the filter using a suitable name.
@register.filter(name='upper')
def upper(value):
  return value.upper()
  
# An upper function that capitalizes the first letter of the word passed to it. We then register the filter using a suitable name.
@register.filter(name='modify_name')
def modify_name(value):
    return value.title()

# An upper function that sets returns a red color. We then register the filter using a suitable name.
@register.filter(name='get_color')
def color(value):
    if value:
        return "#FF0000"

contact.html

 <!-- Loading the custom_tags file to avail our tags and filters -->
{% load custom_tags %}

{% block content %}

{% for contact in contacts %}
<div class="flex-box-container">
  <!-- We now use the get_color and upper filters to change color and capitalize the contact name respectively -->
    <div style="background-color: {{contact.name|get_color}};"><p >{{contact.name|upper}}</p></div>
    <div><b>Created:</b> {{ contact.date }}</div>
</div>
{% endfor %}

{% endblock content %}

最终的视图将如下图所示。

Contact page with the filters

upper 过滤器将联系人的名字大写,而get_color 过滤器则为 div 设置了新的颜色。

同样,你也可以创建你的自定义过滤器,以满足你对模板的任何需求。

你应该检查分配给你的视图的名称。它们应该与@register.filter() 中使用的名称一致。例如,使用color ,而不是get_color ,会导致错误。你可能还需要考虑Django的过滤器的自动转义行为。

编写自定义模板标签

模板标签比过滤器更高级。它们的强大之处在于,它们可以处理任何数据,并使其对任何模板可用,而不管执行的是什么视图。Django提供了两个常用的辅助函数来创建标签。

  1. 简单标签。
  2. 包容性标签。

我们将在我们的custom_tags.py 文件中实现这些标签。

简单标签

这些标签接受任意数量的参数,并在一些处理后返回一个结果。简单标签是一个函数,它接受一个或多个参数,将其包装在一个渲染函数中,并在模板系统中注册。

我们将做两个简单标签的例子。我们的第一个简单标签将计算我们拥有的联系人的数量。第二个函数将获得当前日期,格式为d/m/y

custom_tags.py 中的代码如下。

import datetime

# Create the register instance by initializing it with the Library instance.
from Django import template
register = template.Library()

# An upper function that capitalizes word passed to it.
@register.filter(name='upper')
def upper(value):
  return value.upper()

# An upper function that capitalizes the first letter of the word passed to it.
@register.filter(name='modify_name')
def modify_name(value):
    return value.title()

# An upper function that sets returns a red color.
@register.filter(name='get_color')
def color(value):
    if value:
        return "#FF0000"

# A function that sets returns the number of contacts.
@register.simple_tag(name='my_contacts')
def my_contacts():
    return Contact.objects.all().count()

# A function that sets returns the current date.
@register.simple_tag(name='current_date')
def current_date(format):
    return datetime.datetime.now().strftime(format)

把HTML改成这样。


 <!-- Loading the custom_tags file to avail our tags and filters -->
{% load custom_tags %}

{% block content %}
<!-- Using the my_contacts simple tag -->
<h3>You have {% my_contacts %} contacts</h3>

{% for contact in contacts %}
<div class="flex-box-container">
  <!--Using the get_color and upper filters to change color and capitalize the contact name respectively -->
    <div style="background-color: {{contact.name|get_color}};"><p >{{contact.name|upper}}</p></div>
    <!-- Using the current_date simple tag -->
    <div><b>Created:</b>  {% current_date "%d/%m/%Y" %} </div>
</div>
{% endfor %}

{% endblock content %}

由此产生的模板将如下图所示。

Contact page with the filters and simple tags

同样地,你可以创建你的简单标签,并以你认为合适的方式使用它们。

包含性标签

这些标签通过渲染另一个模板来工作,当处理要在几个页面上找到的信息时,它们是必不可少的。

让我们创建一个简单的包含标签,计算用户的数量。

创建一个users.html 文件,该文件将由包含标签渲染。

在你的custom_tags.py 文件中,编辑并追加如下内容。

from django.contrib.auth.models import User
#  Create show_users inclusion tag that will return all users and register it and indicate that it's going to render a users.html view.

@register.inclusion_tag('users.html')
def show_users():
      obj = User.objects.values_list('username', flat=True)
      return {'users': obj}

模板文件users.html ,看起来将如下图所示。

<ul>
{% for user in users %}
    <li> {{ user }} </li>
{% endfor %}
</ul>

然后使contact.html ,看起来像这样。

 <!-- Loading the custom_tags file to avail our tags and filters -->
{% load custom_tags %}


{% block content %}
<-- Using the my_contacts simple tag -->
<h3>You have {% my_contacts %} contacts</h3>

{% for contact in contacts %}
<div class="flex-box-container">
  <!--Using the get_color and upper filters to change color and capitalize the contact name respectively-->
    <div style="background-color: {{contact.name|get_color}};"><p >{{contact.name|upper}}</p></div>
    <!-- Using the current_date simple tag -->
    <div><b>Created:</b>  {% current_date "%d/%m/%Y" %} </div>
</div>
{% endfor %}
<!--using the show_users inclusion tag -->
{% show_users %}
{% endblock content %}

现在产生的模板将如下图所示。

Contact page with filters and the tags

注意,通过添加show_users 标签,我们现在在联系人下面添加了一个用户。

总结

你现在已经成功创建了你的自定义模板标签和过滤器。你现在应该能够创建新的模板标签和过滤器,并在你的Django应用程序中需要的地方应用它们。