☰
Django新手入门:从零搭建带后台的博客实战指南
2026/10/24 5:52:45 网站建设 项目流程

1. 开始之前:我为什么建议新手直接选Django

如果你刚接触Python Web开发,大概率会在Flask和Django之间反复纠结。我当年也一样,先花了三天用Flask搭了个小博客,然后遇到用户登录、后台管理、数据库迁移这些问题时,发现自己要装的插件比框架本身还多。后来换到Django,才真正体会到什么叫“省心”——用户认证、Admin后台、ORM、表单处理、路由系统全是内置的,装好就能用,不需要自己东拼西凑。

这一章不会长篇大论讲Django的历史或者说它的社区有多庞大,我直接告诉你它能做什么、解决什么问题、适合谁:

  • Django适合做内容型网站、企业级应用、电商平台、社交类产品,几乎覆盖了Web开发的常见场景。
  • 它自带一套完整的“全家桶”,从数据库操作到HTTP响应,从用户登录到后台管理,都不用额外找第三方库。
  • 它适合除了学习框架本身之外,还想要一个“能直接上线”的项目的人。不夸张地说,用Django从零搭建一个带用户系统、数据库和后台管理的网站,最快半天就能跑通。

这篇文章就是我的个人实操笔记,按我实际带新人时的习惯来写。我不会把Django搜刮出来的所有特性都列一遍,只讲一个新手真正会用到的、且能帮你建立起正确心智模型的内容。你跟着我一步步做完一个小项目,就足以理解Django的核心运作方式。

2. 核心设计思路:Django的“约定优于配置”到底方便在哪里

2.1 为什么Django被叫做Web开发的“瑞士军刀”

“瑞士军刀”这个外号并不是营销话术,而是确实符合它的性格。一个成熟框架的核心价值不在于功能多,而在于你遇到问题时它大概率已经替你踩过坑了。Django从2005年诞生到现在,经历了大量真实项目的检验,很多Web开发的通用问题,它都有官方的、默认的、经过验证的解决方案。

拿认证系统举例。在Flask里要实现用户注册、登录、注销、密码重置、记住我、权限控制这几个功能,需要引入Flask-Login、Flask-Mail、Flask-Principal等好几个库,还得自己设计数据表结构。在Django里,django.contrib.auth自带完整的User模型和认证视图,你只需要配置两三个URL路径,页面模板用自己的设计即可。后台管理更是直接赠送,你定义好数据模型,Admin页面自动生成增删改查界面。

这种“默认就给全套”的思路,会让新人产生两个极端感受:要么觉得方便到难以置信,要么觉得臃肿到难以理解。我的建议是,你先把Django当作一个整体来接受,等熟悉之后再拆开来看它每个部件是什么,不要一开始就试图抵制它的设计哲学。就像你用智能手机,不需要先学会ARM架构才能打电话。

2.2 MTV模式与MVC的区别:换个名字而已

很多教程一上来就讲Django的MTV(Model-Template-View)模式,然后跟传统的MVC(Model-View-Controller)做对比,把新手绕得晕头转向。说白了,Django的MTV就是MVC的一种变体,只是把View拆成了Template和View两层:

  • Model对应数据库表结构,跟MVC的Model完全一致;
  • Template对应HTML模板文件,就是MVC里的View,负责展示;
  • View对应业务逻辑处理函数,相当于是MVC里的Controller,负责接收请求、处理数据、决定返回什么内容。

你不需要死记这个概念,只需要理解一个请求的流转路径就够了:用户在浏览器地址栏输入URL,Django的URL分发器根据路径找到对应的View函数,View函数通过Model读取数据库,把取到的数据传给Template,Template渲染成HTML页面再返回给浏览器。整条链路非常清晰。

我教新人的时候特别喜欢画这条流转链,因为一旦理解了这个过程,后面所有Django知识都能对号入座。学View的时候你知道了“这里写业务逻辑”,学Model的时候你知道了“这里操控数据库”,学Template的时候你知道了“这里展示变量和循环”——框架的每个部件各司其职,绝不越界。

2.3 “电池全内置”哲学:Django替你决定好了一部分方案

Django的官方哲学是“内置你要用到的所有东西”(Batteries included)。密码哈希、CSRF防护、SQL注入防护、XSS防护这些安全机制,它全都在框架层面内置好了,你只需要开启配置就能获得保护。这跟“自己组装”的微框架形成了鲜明对比,也决定了Django的上手门槛比Flask高,但出问题的概率低很多。

以一个新手的视角来看,这种设计最大的价值在于:你不需要在一开始就做太多技术选型的决策。数据库需要用哪个?Django默认配好了SQLite,零配置即可开始。后台管理用什么方案?Django自带Admin。表单校验怎么做?Django Forms帮你在后端做二次验证。这些决策权先交出去,等你真正理解了需求,再去替换成PostgreSQL、自定义表单页面等高级配置也不迟。

3. 环境准备与项目骨架:动手前的关键三步

3.1 虚拟环境与Django安装

我强烈建议任何Python项目都用虚拟环境,Django项目更是如此。不同项目可能依赖不同版本的Django,如果你全部装到全局环境里,迟早会因为依赖冲突而崩溃。装虚拟环境的工具我推荐用Python自带的venv,简单干净,不需要额外学习其他工具。

# 创建项目目录并进入 mkdir myblog cd myblog # 创建虚拟环境 python -m venv venv # 激活虚拟环境(Windows) venv\Scripts\activate # 激活虚拟环境(macOS/Linux) source venv/bin/activate # 安装Django(当前稳定版本) pip install django

安装完成后,可以用python -m django --version确认版本号。不同版本之间的配置写法略有差异,但核心思想一致。我写这篇时的Django版本是5.x,如果你用的是更早的3.x或4.x,大多数代码依然可以直接跑。

3.2 创建项目与App:先理解这两个概念的区别

Django里有两个容易混淆的名词:Project(项目)和App(应用)。我打个比方:Project是你的整个网站,比如一个博客平台;App是网站里的一个功能模块,比如文章模块、用户模块、评论模块。一个Project可以包含多个App,一个App也可以被多个Project复用。

# 创建项目 django-admin startproject myblog . # 创建应用 python manage.py startapp blog

注意我创建项目时后面加了.,这表示在当前目录生成项目文件,而不是再嵌套一层同名目录。这个细节很多教程没讲,但我实际操作中发现不加这个点会让目录结构变得很别扭。

创建完成后你会看到一个典型的Django目录结构:manage.py是命令行工具入口,myblog/目录是项目配置目录,blog/目录是你的应用代码。接下来的核心操作基本都在blog/里进行。

3.3 settings.py里必须搞清楚的基础配置

新人打开settings.py会看到一大堆配置项,我先只讲三个立刻需要理解的,其他可以后续慢慢看:

  • INSTALLED_APPS:这个列表告诉Django哪些应用可用。你新建的App必须手动加入这个列表,Django才会识别它的模型、模板和静态文件。
  • DATABASES:数据库连接配置。默认是SQLite3,开发阶段直接使用,不需要任何额外设置。将来换PostgreSQL时,只需要改这里的引擎和连接参数。
  • TEMPLATES:模板引擎配置。默认使用Django Template Language(DTL),你也可以换成Jinja2,但大多数情况下DTL完全够用。

修改myblog/settings.py里的INSTALLED_APPS,把blog加进去:

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', # 这里添加你自己的应用 ]

4. 第一个核心环节:模型设计与数据库操作

4.1 用Model类描述数据:不用写一行SQL

对新手来说,Django的ORM(对象关系映射)是最大的福利之一。你不需要写SQL语句,只需要用Python类来定义数据结构,Django会自动帮你创建对应的数据表。

我以上面创建的博客App为例,设计一篇文章的数据模型:

from django.db import models from django.utils import timezone from django.contrib.auth.models import User class Post(models.Model): title = models.CharField('标题', max_length=200) content = models.TextField('正文') author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者') created_at = models.DateTimeField('创建时间', default=timezone.now) updated_at = models.DateTimeField('更新时间', auto_now=True) class Meta: ordering = ['-created_at'] verbose_name = '文章' verbose_name_plural = '文章' def __str__(self): return self.title

字段类型是我见过新人最容易迷茫的地方,这里给出最常见的几种及其使用场景:

  • CharField:定长文本,适合标题、用户名等短内容,必须指定max_length;
  • TextField:不定长文本,适合正文、简介等长内容;
  • IntegerField:整数字段,适合年龄、计数等;
  • DateTimeField:日期时间字段,适合发布时间、更新时间;
  • ForeignKey:外键,表示一对多关系,比如一篇文章属于一个作者;
  • BooleanField:布尔字段,适合是否删除、是否发布等标记位。

4.2 迁移命令的运作逻辑:Django如何把Model变成数据表

模型定义好之后,需要生成并执行迁移命令,Django才会真正创建数据表。两条命令一套操作,很多初级教程只告诉你“输入这两行命令就好”,但没说它们各自在干嘛:

python manage.py makemigrations python manage.py migrate

makemigrations是“根据模型的变化生成迁移文件”,它会去对比模型定义和当前数据库快照,生成一个Python文件描述“应该怎么改”。migrate是“执行所有未执行的迁移文件”,真正对数据库进行增删改表的操作。如果你修改了模型,需要重新执行makemigrations和migrate,这个过程可以重复无数遍,不用担心数据丢失,因为Django会智能判断哪些迁移已经执行过。

在迁移之后还会遇到一个非常容易被忽略的问题:如果你改动了某个模型字段且该表里已经有数据,Django会提示你提供默认值。这时要么给字段设置default,要么在命令交互时输入一个临时值,总而言之就是别想着“表都建了还能随便改”。从实际经验来看,我先给所有字段都加上合理的默认值或允许为空,再跑迁移,能省去很多提示交互。

4.3 用Django Shell交互式验证模型

数据模型定义完,你需要快速验证它是否正常工作。Django提供一个交互式Shell,直接在里面操作数据库对象,是调试模型最快的方式:

python manage.py shell

进入Shell后,你可以执行以下操作:

# 创建用户(Django自带的User模型) from django.contrib.auth.models import User user = User.objects.create_user(username='demo', password='demo123') # 创建文章 from blog.models import Post post = Post.objects.create(title='我的第一篇文章', content='Hello Django', author=user) # 查询文章 Post.objects.all() Post.objects.filter(author=user).count() # 更新文章 post.title = '修改后的标题' post.save()

这里我建议新人多花十分钟做几种查询练习:filter()、exclude()、get(),以及它们的链式操作。我在项目里最常用的查询模式,比如“最近发布的公开文章”“某个用户的所有文章”其实都是这些基础操作的组合。

5. 核心逻辑环节:视图、URL与模板的协同配合

5.1 视图函数怎么写:从“请求”到“响应”的关键桥梁

视图(View)是Django处理业务逻辑的核心。你用视图函数接收浏览器发来的HTTP请求,在函数体内做各种数据处理,最终返回一个HTTP响应。一个最简单也最常见的视图函数长这样:

from django.shortcuts import render, get_object_or_404 from .models import Post def post_list(request): posts = Post.objects.all() return render(request, 'blog/post_list.html', {'posts': posts}) def post_detail(request, pk): post = get_object_or_404(Post, pk=pk) return render(request, 'blog/post_detail.html', {'post': post})

第一段代码里,render()是快捷函数,它负责三件事:加载模板、把数据填充进模板、返回渲染好的HTML页面。第二段里的get_object_or_404()的作用尤为巧妙:如果根据主键没查到文章就直接返回404页面,如果查到了就正常返回文章详情,省掉了一大段try except代码。这两个快捷函数是Django最常用的“语法糖”,我实际开发中每天都在用。

视图可以更复杂,比如处理表单提交、进行权限判断、操作Session,但它本质上始终是那三步:接收请求、处理数据、返回响应。理解了这个本质,一切花哨的功能都只是往这个框架里填充内容。

5.2 URL路由:把网址映射到视图

Django的路由系统定义在项目的urls.py文件中。路由的作用就是让用户访问某个网址时,Django知道应该调用哪个视图函数。

# myblog/urls.py(项目根路由) from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('blog/', include('blog.urls')), ] # blog/urls.py(应用内部路由) from django.urls import path from . import views app_name = 'blog' urlpatterns = [ path('', views.post_list, name='post_list'), path('post/<int:pk>/', views.post_detail, name='post_detail'), ]

这里有三个关键点新手必须掌握:

  • path()函数的第一个参数是URL路径,支持动态参数,比如<int:pk>会匹配任意整数并赋值给视图函数里的pk参数;
  • name参数给路由起了“别名”,这样模板里就能用{% url 'blog:post_detail' post.id %}来生成链接,而不是硬编码网址。以后路径改了,模板不用改。
  • include()把应用自己的路由挂载到项目的总路由下。这是一种模块化管理方式,一个项目里有十个App也不会乱。

为什么推荐用name而不是直接写死网址?我吃过亏。以前写项目时在模板里直接写了/blog/post/3/这样的链接,后来需求变了路径变成了/article/3/,我只能全局搜索一个个改。用路由别名后,只改urls.py一处,所有引用它的模板全部自动更新。

5.3 Django模板语言:在HTML里写逻辑

Django的模板语言允许你在HTML文件里插入动态数据和控制逻辑。它特意不做成“完全Python”的语法,而是保持简单的标签系统,防止你在模板里写过于复杂的业务逻辑。下面是一个简单的列表模板:

<!DOCTYPE html> <html> <head> <title>我的博客</title> </head> <body> <h1>文章列表</h1> {% for post in posts %} <div> <h2><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a></h2> <p>{{ post.content|truncatechars:50 }}</p> <p>作者:{{ post.author.username }} | 发布时间:{{ post.created_at|date:"Y-m-d H:i" }}</p> </div> {% empty %} <p>还没有任何文章。</p> {% endfor %} </body> </html>

需要重视的模板语法有三个:{{ 变量 }}用于输出数据,{% 标签 %}用于做循环、判断等逻辑,{{ 变量|过滤器 }}用于格式化数据。truncatechars:50是截断字符的过滤器,date:"Y-m-d H:i"是日期格式化过滤器,这类内置过滤器可以帮你省去在视图里写大量格式化代码的麻烦。

我在给新人的模板建议中说三句话:模板里只做展示,别做复杂业务逻辑;能通过过滤器解决的操作就别在视图里预处理;需要循环时永远用{% empty %}做兜底处理,否则空列表会在页面上留下一块异常难看且不给人提示的区域。

6. 实操记录:5分钟跑通一个带后台的迷你博客

6.1 Django Admin后台:从零到可用的最快路径

Django最让人“艾玛真香”的功能就是自带Admin后台。到这一步,你不需要写任何后台代码,只需要把数据模型注册到Admin里,就能获得一个完整的后台管理界面,对文章进行增删改查。

在blog/admin.py里加两行代码:

from django.contrib import admin from .models import Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ('title', 'author', 'created_at', 'updated_at') list_filter = ('author', 'created_at') search_fields = ('title', 'content')

然后创建一个超级管理员账号并启动开发服务器:

python manage.py createsuperuser python manage.py runserver

打开http://127.0.0.1:8000/admin/,输入刚才设置的账号密码,你就能在可视化界面上发布文章、编辑内容。list_display、list_filter、search_fields这三个配置是我每次写Admin都会用到的“铁三角”:列表显示关键列、侧边栏过滤、顶部搜索框,三个配置加起来用户的后台操作效率会大幅提升。

对于个人项目或小团队内部系统,Django Admin甚至可以当主后台直接用。我见过不少企业用它做后台管理系统,原因很简单:开发成本极低,字段变更时自动同步界面,安全机制也健壮。这就像是框架给你配了一个“企业级管理的标准版本”,而它只是整个Django工具箱中的一项功能。

6.2 模板美化与静态文件加载

默认的HTML没有样式,很难看。这一步我们需要让页面加载CSS文件,这也是新手遇到的一个常见坑:模板写了<link rel="stylesheet" href="{% static 'css/style.css' %}">但页面就是没样式。

需要在settings.py里确认配置,并且确保模板顶部加载了静态文件标签:

# settings.py STATIC_URL = '/static/'
<!-- 模板文件顶部 --> {% load static %} <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="{% static 'css/style.css' %}"> </head>

开发模式下runserver会自动处理静态文件,但生产环境部署时你要额外配置STATIC_ROOT并执行python manage.py collectstatic,把所有应用里的静态文件收集到一个统一目录,供反向代理服务器访问。这个坑是很多新手部署时卡很久的问题,我这里提前给你打预防针。

6.3 用一条命令看全貌:整体跑通的感受

当你完成上述所有步骤,启动服务后在浏览器里看到自己的博客页面、能通过Admin后台发布新文章、文章列表自动更新时,你已经完整走通了Django的主要工作流:配置路由、定义模型、创建视图、渲染模板。这四个环节就是Django开发的核心闭环,之后不管你做什么功能,都沿着这条闭环迭代。

我在带新人实操时,会把复杂的业务需求都拆成这四个环节来思考:这个新功能需要哪些数据?存哪个模型里?需要哪些页面?每个页面需要哪些数据?页面上怎么展示?想清楚了,写代码就只是翻译过程了。

7. 常见问题速查与避坑指南

7.1 遇到最多的问题:迁移和数据库

新手在开发中最容易遇到的问题是迁移失败。我总结几个高频情况:

  • 报错No changes detected:说明模型没有变化,或者你忘记把App加到INSTALLED_APPS里,检查一下是否把blog添加到了配置列表。
  • 报错Table already exists:说明迁移文件与数据库状态不一致。最稳妥的解决办法是:删除数据库文件(仅开发阶段可行),删除所有migrations目录下的迁移文件(保留__init__.py),重新执行makemigrations和migrate。
  • 报错Field 'id' expected a number but got 'xxx':设置主键值的类型不对,检查URL里的<int:pk>是否传了真正的整数。

数据丢失问题我多提一句,很多在开发阶段可以暴力重置,但一旦项目上了生产,千万别乱删数据库和迁移文件。正确的是用python manage.py migrate --plan查看迁移影响,用python manage.py showmigrations确认迁移状态,再决定下一步操作。

7.2 表单提交与CSRF令牌:不安全的常见坑

Django默认开启了CSRF防护,所有POST表单里必须包含{% csrf_token %}。有些新手没加这个标签,提交表单时一直报403错误,然后百思不得其解。解决办法很简单:在<form>标签内加上{% csrf_token %}即可。这是一个安全功能,别为了方便把它关闭,否则你的站点很容易遭受跨站请求伪造攻击。

7.3 静态文件404:样式加载不出来的原因

这个问题在开发阶段频繁出现。先确认模板里用了{% load static %},再确认文件放在了正确的目录下。Django在每个App里的static/目录下查找静态文件,也就是blog/static/css/style.css这种路径。如果你把文件放到了项目根目录的某个static文件夹里,需要在settings.py里额外配置STATICFILES_DIRS:

STATICFILES_DIRS = [ BASE_DIR / 'static', ]

7.4 中文显示乱码与编码问题的处理

在数据库和页面中可能会出现中文乱码。检查三处:settings.py里确保LANGUAGE_CODE = 'zh-hans'和TIME_ZONE = 'Asia/Shanghai';确保.py和.html文件都保存为UTF-8编码;确保数据库连接的编码是UTF-8。默认SQLite对Unicode支持良好,只要文件编码正确,一般不会出现乱码。

7.5 开发常见问题速查表

问题现象常见原因快速排查方法
页面404URL写错或视图未定义检查urls.py的路径和视图函数名
页面500视图有语法错误或模型有问题看runserver命令行输出的错误堆栈
表单提交报403缺少CSRF令牌在表单里加入{% csrf_token %}
样式不加载静态文件路径不对检查{% static %}标签和目录结构
数据库查询报错ORM语义用错打印查询语句检查:打印QuerySet.query

8. 进阶方向:搞定这些你就离生产环境不远了

当一个Django项目跑通基础页面之后,下一步怎么走?很多新人从Demo到真实项目之间有个断层,不知道怎么补齐。我给你几条切实际的前进路线:

首要任务是把默认的用户模型换成自定义模型。Django的User模型内置字段有限,总有一天你需要加手机号、头像、性别等字段。直接在项目一开始就定义自己的用户模型(继承AbstractUser),可以省去后面漫长的数据迁移痛苦。这个决定越早做越好,最好在第一次migrate之前就完成。

其次是掌握基于类的通用视图(Class-Based Views,简称CBV)。函数视图简单直接,但在处理“展示对象列表”“展示对象详情”“创建对象”这些重复场景时乏味且容易出错。Django提供了一批通用视图类,只需要指定模型和模板路径,就能实现90%的常见功能。我们需要做的是理解一个CBV内部发生了什么,才能灵活定制它。

然后是Django REST Framework(DRF)。如果你的项目需要将数据提供给小程序、移动App或前端框架,那么DRF几乎是必须掌握的技能。它构建在Django之上,用同样的MTV模式处理JSON请求和响应。学好DRF之后,你的Django技能就会从“只能做服务端渲染”扩展到“既能渲染页面又能提供API”。

最后一项是部署上线。开发时用runserver,但线上环境一定要用Gunicorn或Uvicorn这类WSGI/ASGI服务器,配合反向代理(比如Nginx)来处理静态文件和安全策略。这一部分的坑通常在静态文件、数据库连接、环境变量管理三个方向,但我觉得部署意识和积累同样重要。

9. 给我新人的几个真话

到这里,新手入门Django最核心的知识链已经完整了:安装、项目骨架、模型设计、视图逻辑、模板展示、Admin后台、问题排查和进阶方向。接下来我要说几句可能不完全中听的经验。

不要死磕“必须理解每一个源码细节才往下走”。Django是个大框架,你不可能一次学完,也没必要。你只需要先掌握我用到的这些核心链路,其余的遇到一个学一个,这才是真实的开发节奏。任何框架的学习,都是“用进废退”,你不需要读完整本参考书才动手写,你写三个小项目之后的收获,比读三遍文档多得多。

不要迷信“最佳实践”。很多人一上来就追求所谓的“完美项目结构”和“最佳性能”,但刚学阶段最重要的只有一件事:跑起来。哪怕你的代码不怎么优雅、逻辑不够健壮,没关系。只要你亲手把一个功能完整地跑通,你对Django的理解就已经变成肌肉记忆,而不是纸面知识。优化和重构建立在正确运行的基础上,而不是在臆想中。

不要把数据库和迁移当成定时炸弹。我见过不少朋友因为“怕把数据弄坏”而不敢改模型,然后绕着弯子写各种补救代码。实际上,开发阶段的数据库几乎没有不可恢复的数据。即使真弄乱了,删除迁移文件和数据库文件重新生成也只需要几分钟。大胆改,多跑迁移,才能在错误中学会正确的方式。

写代码遇到环境问题了,我的建议是先理清逻辑,不要盲目搜索改来改去。程序员的大部分时间其实都花在找问题上,这个过程虽然枯燥,但你每次把那些莫名其妙的报错排查完后,才会真正成为能独当一面的开发者。

10. 最后给你一个练手建议

如果你现在想用Django练手但不知道做什么项目,我的建议是做一个“待办事项管理工具”,数据模型只需一个Task表,包含标题、是否完成、创建时间、截止日期;页面只需列表视图与新增表单;后台用Django Admin管理所有任务。这个项目麻雀虽小五脏俱全,你会完整走过模型、视图、模板、表单、URL路由、Admin注册、迁移和部署这条全链路。

做完这个之后,把系统改成“记账本”,增加分类、金额、日期,再加一点统计图表;再改成“学习打卡”,增加连续打卡记录逻辑。每换一个场景,你都会遇到新的业务需求和新的数据关系,而这正是你成长的核心。我也还是在实践中碰到问题与解决问题的过程中不断成长,Django像瑞士军刀,既有现成工具帮你快速完成小任务的能力,也具备应对复杂产品需求的深度,关键在于你愿不愿意拿起它用力去用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询