每天40分玩转Django:Django模板系统

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 基本语法示例

html 复制代码
<!-- 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 markdown

register = 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 Post
    return Post.objects.count()

# 自定义包含上下文的标签
@register.inclusion_tag('blog/includes/latest_posts.html')
def show_latest_posts(count=5):
    from blog.models import Post
    latest_posts = Post.objects.order_by('-publish')[:count]
    return {'latest_posts': latest_posts}

四、模板继承

4.1 基础模板

html 复制代码
<!-- 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 页面模板

html 复制代码
<!-- 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 静态文件使用示例

html 复制代码
<!-- 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示例

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示例

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);
            }
        });
    });
});

六、最佳实践

  1. 模板组织:

    • 使用清晰的目录结构
    • 根据功能模块划分模板
    • 复用代码放入includes目录
  2. 性能优化:

    • 使用模板片段缓存
    • 合理使用模板继承
    • 避免过多的模板嵌套
  3. 安全考虑:

    • 默认启用HTML转义
    • 谨慎使用safe过滤器
    • 注意XSS攻击防范

七、常见问题和解决方案

  1. 静态文件不显示:
python 复制代码
# urls.py (开发环境)
from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  1. 模板找不到:

    • 检查TEMPLATES设置
    • 确认模板文件位置
    • 检查应用是否已安装
  2. 上下文处理器:

python 复制代码
# blog/context_processors.py
def categories(request):
    from blog.models import Category
    return {
        'categories': Category.objects.all()
    }

八、作业和练习

  1. 创建一个完整的博客首页模板
  2. 实现文章详情页模板
  3. 添加分类和标签侧边栏
  4. 实现评论系统模板
  5. 添加分页功能

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

相关推荐
bobz9651 分钟前
ovs patch port 对比 veth pair
后端
Asthenia041211 分钟前
Java受检异常与非受检异常分析
后端
uhakadotcom25 分钟前
快速开始使用 n8n
后端·面试·github
JavaGuide31 分钟前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz96542 分钟前
qemu 网络使用基础
后端
Asthenia04121 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04121 小时前
Spring 启动流程:比喻表达
后端
Asthenia04122 小时前
Spring 启动流程分析-含时序图
后端
ONE_Gua2 小时前
chromium魔改——CDP(Chrome DevTools Protocol)检测01
前端·后端·爬虫
致心2 小时前
记一次debian安装mariadb(带有迁移数据)
后端