第7章:模板系统
7.3 自定义模板
自定义过滤器
Django允许你创建自定义过滤器来扩展模板功能。自定义过滤器是一个Python函数,最多接收两个参数:
- 变量的值(输入)
- 参数的值(可选)
首先在应用目录下创建templatetags目录,并添加__init__.py文件:
myapp/
templatetags/
__init__.py
custom_filters.py然后在custom_filters.py中定义过滤器:
python
from django import template
register = template.Library()
# 简单过滤器示例
@register.filter
def lower(value):
"""将字符串转换为小写"""
return value.lower()
# 带参数的过滤器示例
@register.filter
def truncate_chars(value, max_length):
"""截断字符串到指定字符数"""
if len(value) > max_length:
return value[:max_length] + '...'
return value
# 更复杂的过滤器示例
@register.filter
def word_count(value):
"""计算文本中的单词数"""
return len(value.split())
@register.filter
def multiply(value, arg):
"""将数值乘以参数"""
try:
return float(value) * float(arg)
except (ValueError, TypeError):
return 0
@register.filter
def highlight_search(text, search_term):
"""高亮搜索关键词"""
if search_term:
return text.replace(
search_term,
f'<mark>{search_term}</mark>'
)
return text在模板中使用自定义过滤器:
html
{% load custom_filters %}
<p>标题:{{ title|lower }}</p>
<p>摘要:{{ content|truncate_chars:100 }}</p>
<p>字数:{{ content|word_count }}</p>
<p>价格:{{ price|multiply:1.2|floatformat:2 }}</p>
<p>搜索结果:{{ content|highlight_search:query }}</p>自定义标签
自定义标签比过滤器更复杂,可以执行更复杂的逻辑。它们分为几种类型:
- 简单标签
- 包含标签
- 赋值标签
在templatetags/custom_tags.py中定义标签:
python
from django import template
from django.utils.safestring import mark_safe
from ..models import Article, Category
register = template.Library()
# 简单标签示例
@register.simple_tag
def total_articles():
"""返回文章总数"""
return Article.objects.count()
@register.simple_tag
def article_count_by_category(category_slug):
"""返回指定分类的文章数"""
try:
category = Category.objects.get(slug=category_slug)
return category.articles.count()
except Category.DoesNotExist:
return 0
# 带参数的简单标签
@register.simple_tag(takes_context=True)
def user_article_count(context):
"""返回当前用户的文章数"""
user = context['user']
if user.is_authenticated:
return Article.objects.filter(author=user).count()
return 0
# 包含标签示例
@register.inclusion_tag('tags/recent_articles.html')
def recent_articles(count=5):
"""显示最近的文章"""
articles = Article.objects.filter(
status='published'
).order_by('-publish_date')[:count]
return {'articles': articles}
# 赋值标签示例
@register.simple_tag
def get_categories():
"""获取所有分类"""
return Category.objects.all()
# 复杂标签示例
@register.tag
def highlight_text(parser, token):
"""
高亮文本标签
用法:{% highlight_text "搜索词" %}被搜索的文本{% endhighlight_text %}
"""
try:
# 解析标签参数
tag_name, search_term = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError(
"%r tag requires a single argument" % token.contents.split()[0]
)
# 解析标签内容直到endhighlight_text
nodelist = parser.parse(('endhighlight_text',))
parser.delete_first_token()
return HighlightTextNode(nodelist, search_term)
class HighlightTextNode(template.Node):
def __init__(self, nodelist, search_term):
self.nodelist = nodelist
self.search_term = template.Variable(search_term)
def render(self, context):
# 渲染标签内容
text = self.nodelist.render(context)
try:
search_term = self.search_term.resolve(context)
# 高亮搜索词
highlighted = text.replace(
search_term,
f'<mark>{search_term}</mark>'
)
return mark_safe(highlighted)
except template.VariableDoesNotExist:
return text在模板中使用自定义标签:
html
{% load custom_tags %}
<!-- 简单标签 -->
<p>总文章数:{% total_articles %}</p>
<p>Python分类文章数:{% article_count_by_category "python" %}</p>
<p>您的文章数:{% user_article_count %}</p>
<!-- 包含标签 -->
{% recent_articles 10 %}
<!-- 赋值标签 -->
{% get_categories as categories %}
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
<!-- 复杂标签 -->
{% highlight_text "Django" %}
Django是一个高级Python Web框架,它鼓励快速开发和干净、实用的设计。
{% endhighlight_text %}包含标签的模板文件 templates/tags/recent_articles.html:
html
<div class="recent-articles">
<h3>最近文章</h3>
<ul>
{% for article in articles %}
<li>
<a href="{{ article.get_absolute_url }}">{{ article.title }}</a>
<span class="date">{{ article.publish_date|date:"m-d" }}</span>
</li>
{% empty %}
<li>暂无文章</li>
{% endfor %}
</ul>
</div>模板上下文处理器
模板上下文处理器是在所有模板上下文中自动添加变量的函数。它们在settings.py的TEMPLATES配置中定义。
创建context_processors.py:
python
from django.conf import settings
def site_info(request):
"""站点信息上下文处理器"""
return {
'site_name': getattr(settings, 'SITE_NAME', '我的网站'),
'site_description': getattr(settings, 'SITE_DESCRIPTION', '一个Django网站'),
}
def user_permissions(request):
"""用户权限上下文处理器"""
if request.user.is_authenticated:
return {
'user_permissions': request.user.get_all_permissions(),
'is_admin': request.user.is_staff,
}
return {}
def common_data(request):
"""常用数据上下文处理器"""
from ..models import Category
try:
categories = Category.objects.all()[:10]
except:
categories = []
return {
'common_categories': categories,
'current_year': datetime.now().year,
}在settings.py中注册上下文处理器:
python
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
# 自定义上下文处理器
'myapp.context_processors.site_info',
'myapp.context_processors.user_permissions',
'myapp.context_processors.common_data',
],
},
},
]在任何模板中使用上下文处理器提供的变量:
html
<!-- 所有模板都可以访问这些变量 -->
<header>
<h1>{{ site_name }}</h1>
<p>{{ site_description }}</p>
</header>
<nav>
<ul>
{% for category in common_categories %}
<li><a href="{{ category.get_absolute_url }}">{{ category.name }}</a></li>
{% endfor %}
</ul>
</nav>
<footer>
<p>© {{ current_year }} {{ site_name }}</p>
{% if is_admin %}
<p><a href="/admin/">管理后台</a></p>
{% endif %}
</footer>静态文件处理
在模板中正确引用静态文件(CSS、JavaScript、图片等):
html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>我的网站</title>
<!-- CSS文件 -->
<link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/responsive.css' %}">
</head>
<body>
<!-- 图片 -->
<img src="{% static 'images/logo.png' %}" alt="Logo">
<div class="content">
<!-- 页面内容 -->
</div>
<!-- JavaScript文件 -->
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
<!-- 带版本控制的静态文件 -->
<script src="{% static 'js/app.js' %}?v=1.0"></script>
</body>
</html>在开发环境中,需要在settings.py中配置静态文件:
python
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / "staticfiles"在生产环境中,通常需要配置Web服务器(如Nginx)来直接提供静态文件,以提高性能。
小结
自定义模板功能扩展了Django模板系统的能力:
- ✅ 自定义过滤器处理变量格式化
- ✅ 自定义标签实现复杂逻辑
- ✅ 模板上下文处理器全局注入变量
- ✅ 静态文件的正确引用和管理
- ✅ 包含标签和赋值标签的灵活使用
掌握自定义模板功能能够创建更强大和灵活的前端界面。
下一篇
我们将学习Django表单系统。