01-从零入门教程

知识库
知识库文档
/tech-stacks/django/tutorial/01-从零入门教程.md

文档

Django 入门教程 —— MTV 架构与快速建站

本章目标

  • 理解 Django 的 MTV 架构与"电池内置"哲学
  • 掌握模型、视图、模板、路由四大核心
  • 完成一个完整的博客系统 CRUD

1. Django 的 MTV 架构

Django 采用 MTV(Model-Template-View)分层:

          URL Dispatcher
               │
               ▼
    ┌──────────────────────┐
    │   View(业务逻辑)     │  ← "Controller" 的角色
    │   处理请求、协调 Model  │
    │   和 Template           │
    └────┬─────────┬────────┘
         │         │
         ▼         ▼
  ┌──────────┐  ┌──────────┐
  │  Model   │  │ Template │
  │ 数据层   │  │ 表现层   │
  │ ORM + DB │  │ HTML/模板│
  └──────────┘  └──────────┘

与传统 MVC 的对应关系:

  • Model ≈ M
  • Template ≈ V
  • View ≈ C(Controller)

2. 模型(Model)—— 数据层

# blog/models.py
from django.db import models
from django.utils.text import slugify


class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(max_length=50, unique=True, blank=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name


class Post(models.Model):
    title = models.CharField("标题", max_length=200)
    slug = models.SlugField(max_length=200, unique=True)
    body = models.TextField("正文")
    tags = models.ManyToManyField(Tag, related_name="posts", blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["-created_at"]),
            models.Index(fields=["slug"]),
        ]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        from django.urls import reverse
        return reverse("post_detail", kwargs={"slug": self.slug})

模型字段类型速查

字段 用途
CharField(max_length=n) 短文本
TextField() 长文本
IntegerField() 整数
BooleanField() 布尔值
DateTimeField(auto_now_add=True) 创建时间
DateTimeField(auto_now=True) 更新时间
ForeignKey(to, on_delete) 一对多
ManyToManyField(to) 多对多
SlugField() URL 友好字符串
EmailField() 邮箱
ImageField(upload_to=...) 图片上传

查询 API(ORM)

# 基本 CRUD
Post.objects.create(title="Hello", body="World")          # 创建
post = Post.objects.get(slug="hello")                      # 单个查询
posts = Post.objects.filter(tags__name="django")           # 过滤
Post.objects.filter(status="draft").update(status="pub")   # 批量更新
Post.objects.filter(created_at__year=2024).delete()        # 批量删除

# 聚合
from django.db.models import Count, Avg, Sum
Post.objects.aggregate(Count("id"))                        # 总数

# 关联查询
post.tags.all()                                            # 获取文章的所有标签
tag.posts.filter(status="published")                       # 获取标签下已发布文章

# 链式条件
Post.objects.filter(
    models.Q(status="published") & 
    (models.Q(title__icontains="Django") | models.Q(body__icontains="Django"))
)

3. 视图(View)—— 业务逻辑

函数视图 vs 类视图

# 函数视图 —— 简单直接
def post_list(request):
    posts = Post.objects.filter(status="published")
    return render(request, "blog/list.html", {"posts": posts})

# 类视图 —— 可复用、带 mixin
from django.views.generic import ListView, DetailView, CreateView

class PostListView(ListView):
    model = Post
    template_name = "blog/list.html"
    context_object_name = "posts"
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset().filter(status="published")
        tag_slug = self.kwargs.get("tag_slug")
        if tag_slug:
            queryset = queryset.filter(tags__slug=tag_slug)
        return queryset

常用通用视图

类视图 用途 关键属性
ListView 对象列表 model, paginate_by, queryset
DetailView 对象详情 model, slug_field, slug_url_kwarg
CreateView 创建对象 model, fields, success_url
UpdateView 更新对象 同上
DeleteView 删除对象 model, success_url
TemplateView 纯模板 template_name

4. 模板(Template)—— 表现层

<!-- templates/blog/list.html -->
{% extends "base.html" %}

{% block title %}博客文章列表{% endblock %}

{% block content %}
<h1>📝 文章列表</h1>

{% for post in posts %}
    <article>
        <h2><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
        <p>{{ post.body|truncatewords:30 }}</p>
        <div class="meta">
            <time>{{ post.created_at|date:"Y-m-d" }}</time>
            <span class="tags">
                {% for tag in post.tags.all %}
                    <a href="{% url 'post_list_by_tag' tag.slug %}">{{ tag.name }}</a>
                {% endfor %}
            </span>
        </div>
    </article>
{% empty %}
    <p>暂无文章</p>
{% endfor %}

<!-- 分页 -->
{% if page_obj.has_other_pages %}
    <nav class="pagination">
        {% if page_obj.has_previous %}
            <a href="?page={{ page_obj.previous_page_number }}">上一页</a>
        {% endif %}
        <span>第 {{ page_obj.number }} / {{ page_obj.paginator.num_pages }} 页</span>
        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}">下一页</a>
        {% endif %}
    </nav>
{% endif %}
{% endblock %}

模板标签速查

标签 说明
{% extends %} 继承父模板
{% block %} 定义可替换的内容块
{% include %} 引入子模板
{% url "name" %} 反向 URL 解析
{% csrf_token %} CSRF 令牌
{% for %} / {% endfor %} 循环
{% if %} / {% endif %} 条件
{% with %} 变量赋值
{% now "Y-m-d" %} 当前日期时间

模板过滤器

过滤器 效果
`{{ text truncatewords:30 }}`
`{{ date date:"Y-m-d" }}`
`{{ content safe }}`
`{{ text linebreaks }}`
`{{ value default:"暂无" }}`

5. 管理后台自定义

# blog/admin.py
from django.contrib import admin
from .models import Post, Tag


@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    list_display = ["name", "slug"]
    prepopulated_fields = {"slug": ("name",)}


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ["title", "slug", "created_at", "updated_at"]
    list_filter = ["tags", "created_at"]
    search_fields = ["title", "body"]
    prepopulated_fields = {"slug": ("title",)}
    date_hierarchy = "created_at"
    filter_horizontal = ["tags"]
    readonly_fields = ["created_at", "updated_at"]

    fieldsets = [
        ("基本信息", {"fields": ["title", "slug", "body"]}),
        ("分类", {"fields": ["tags"]}),
        ("时间信息", {"fields": ["created_at", "updated_at"]}),
    ]

6. 常用管理命令

python manage.py runserver              # 开发服务器
python manage.py startapp <;app_name>    # 创建应用
python manage.py makemigrations         # 生成迁移文件
python manage.py migrate                # 执行迁移
python manage.py createsuperuser        # 创建管理员
python manage.py shell                  # Django 交互式 Shell
python manage.py collectstatic          # 收集静态文件
python manage.py test                   # 运行测试
python manage.py showmigrations         # 查看迁移状态
python manage.py dbshell                # 数据库命令行

思考题

  1. Django 的 MTV 与经典 MVC 有何异同?为什么 Django 称其 View 为 Controller?
  2. ForeignKeyon_delete=models.CASCADE vs SET_NULL 有何区别?
  3. 什么场景应该使用函数视图而非类视图?
  4. Django 管理后台适合直接给最终用户使用吗?为什么?

信息

路径
/tech-stacks/django/tutorial/01-从零入门教程.md
更新时间
2026/5/30