Django模板系统
一、课程概述
学习项目 | 具体内容 | 预计用时 |
---|---|---|
模板语法 | 变量、标签、过滤器、注释 | 90分钟 |
模板继承 | 模板层级、块、包含 | 60分钟 |
静态文件 | 配置、管理、使用 | 90分钟 |
二、模板基础配置
2.1 模板配置
python"># settings.py
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','blog.context_processors.categories', # 自定义上下文处理器],},},
]
2.2 项目结构
myproject/├── manage.py├── myproject/│ └── settings.py├── templates/│ ├── base.html│ └── blog/│ ├── post_list.html│ ├── post_detail.html│ └── includes/│ ├── header.html│ ├── sidebar.html│ └── footer.html└── static/├── css/├── js/└── images/
三、模板语法
3.1 基本语法示例
<!-- templates/blog/post_list.html -->
{% extends 'base.html' %}
{% load static %}{% block title %}博客文章列表{% endblock %}{% block content %}<div class="posts">{# 这是单行注释 #}{% comment %}这是多行注释可以写很多行{% endcomment %}{# 变量输出 #}<h1>{{ page_title }}</h1>{# 条件判断 #}{% if posts %}{# 循环遍历 #}{% for post in posts %}<article class="post"><h2>{{ post.title }}</h2>{# 过滤器使用 #}<p>{{ post.body|truncatewords:30|linebreaks }}</p><p>作者:{{ post.author.username|default:"匿名" }}</p><p>发布时间:{{ post.publish|date:"Y-m-d H:i" }}</p></article>{% empty %}<p>暂无文章</p>{% endfor %}{% else %}<p>没有找到任何文章</p>{% endif %}</div>
{% endblock %}
3.2 常用过滤器
过滤器 | 说明 | 示例 |
---|---|---|
default | 设置默认值 | {{ value|default:“默认值” }} |
length | 返回长度 | {{ list|length }} |
date | 日期格式化 | {{ date|date:“Y-m-d” }} |
truncatewords | 截断字符串 | {{ text|truncatewords:30 }} |
safe | 禁用转义 | {{ html|safe }} |
upper | 转大写 | {{ string|upper }} |
lower | 转小写 | {{ string|lower }} |
capfirst | 首字母大写 | {{ string|capfirst }} |
3.3 自定义模板标签和过滤器
python"># blog/templatetags/blog_tags.py
from django import template
from django.utils.html import mark_safe
import markdownregister = template.Library()# 自定义过滤器
@register.filter(name='markdown')
def markdown_format(text):return mark_safe(markdown.markdown(text))# 自定义简单标签
@register.simple_tag
def total_posts():from blog.models import Postreturn Post.objects.count()# 自定义包含上下文的标签
@register.inclusion_tag('blog/includes/latest_posts.html')
def show_latest_posts(count=5):from blog.models import Postlatest_posts = Post.objects.order_by('-publish')[:count]return {'latest_posts': latest_posts}
四、模板继承
4.1 基础模板
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>{% block title %}默认标题{% endblock %}</title>{% block css %}<link rel="stylesheet" href="{% static 'css/base.css' %}">{% endblock %}
</head>
<body><header>{% include 'includes/header.html' %}</header><div class="container"><main>{% block content %}{% endblock %}</main><aside>{% block sidebar %}{% include 'includes/sidebar.html' %}{% endblock %}</aside></div><footer>{% include 'includes/footer.html' %}</footer>{% block js %}<script src="{% static 'js/base.js' %}"></script>{% endblock %}
</body>
</html>
4.2 页面模板
<!-- templates/blog/post_detail.html -->
{% extends 'base.html' %}
{% load blog_tags %}{% block title %}{{ post.title }}{% endblock %}{% block css %}{{ block.super }}<link rel="stylesheet" href="{% static 'css/post.css' %}">
{% endblock %}{% block content %}<article class="post-detail"><h1>{{ post.title }}</h1><div class="meta"><span>作者:{{ post.author.username }}</span><span>发布时间:{{ post.publish|date:"Y-m-d H:i" }}</span><span>分类:{{ post.category.name }}</span></div><div class="content">{{ post.body|markdown }}</div><div class="tags">{% for tag in post.tags.all %}<span class="tag">{{ tag.name }}</span>{% endfor %}</div></article>{% show_latest_posts 5 %}
{% endblock %}
五、静态文件处理
5.1 静态文件配置
python"># settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / 'staticfiles'# 开发环境media文件配置
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
5.2 静态文件使用示例
<!-- templates/blog/includes/sidebar.html -->
{% load static %}<div class="sidebar"><div class="profile"><img src="{% static 'images/avatar.png' %}" alt="头像"><h3>{{ user.username }}</h3></div><div class="categories"><h3>文章分类</h3><ul>{% for category in categories %}<li><a href="{% url 'blog:category' category.slug %}">{{ category.name }}<span>({{ category.posts.count }})</span></a></li>{% endfor %}</ul></div>
</div>
5.3 CSS示例
/* static/css/base.css */
:root {--primary-color: #007bff;--secondary-color: #6c757d;--background-color: #f8f9fa;
}body {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;line-height: 1.6;color: #333;background-color: var(--background-color);
}.container {max-width: 1200px;margin: 0 auto;padding: 0 15px;display: grid;grid-template-columns: 3fr 1fr;gap: 30px;
}/* 响应式设计 */
@media (max-width: 768px) {.container {grid-template-columns: 1fr;}
}
5.4 JavaScript示例
// static/js/base.js
document.addEventListener('DOMContentLoaded', function() {// 处理导航菜单const toggleMenu = document.querySelector('.toggle-menu');const nav = document.querySelector('nav');if (toggleMenu) {toggleMenu.addEventListener('click', function() {nav.classList.toggle('active');});}// 处理文章点赞const likeButtons = document.querySelectorAll('.like-button');likeButtons.forEach(button => {button.addEventListener('click', async function() {const postId = this.dataset.postId;try {const response = await fetch(`/api/posts/${postId}/like/`, {method: 'POST',headers: {'X-CSRFToken': getCookie('csrftoken')}});const data = await response.json();this.querySelector('.like-count').textContent = data.likes;} catch (error) {console.error('Error:', error);}});});
});
六、最佳实践
-
模板组织:
- 使用清晰的目录结构
- 根据功能模块划分模板
- 复用代码放入includes目录
-
性能优化:
- 使用模板片段缓存
- 合理使用模板继承
- 避免过多的模板嵌套
-
安全考虑:
- 默认启用HTML转义
- 谨慎使用safe过滤器
- 注意XSS攻击防范
七、常见问题和解决方案
- 静态文件不显示:
python"># urls.py (开发环境)
from django.conf import settings
from django.conf.urls.static import staticif settings.DEBUG:urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
-
模板找不到:
- 检查TEMPLATES设置
- 确认模板文件位置
- 检查应用是否已安装
-
上下文处理器:
python"># blog/context_processors.py
def categories(request):from blog.models import Categoryreturn {'categories': Category.objects.all()}
八、作业和练习
- 创建一个完整的博客首页模板
- 实现文章详情页模板
- 添加分类和标签侧边栏
- 实现评论系统模板
- 添加分页功能
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!