☰
Django入门实战:从零搭建Python Web博客项目全解析
2026/10/15 6:12:46 网站建设 项目流程

如果你用Python写过一点脚本,突然想正儿八经做个Web网站,那“Django”这个名字你是绕不开的。网上很多人管它叫Python Web开发的“瑞士军刀”,因为这个框架确实太全面了:ORM操作数据库、用户登录注册、后台管理系统、模板渲染页面、URL路由分发,几乎你能想到的Web后端功能它都自带。你不用像用Flask那样逐个装第三方库,也不用纠结“要不要引入一个ORM”“登录逻辑自己做还是用现成的”,Django早就给你准备好了——这就是它最大的价值。

这篇内容适合谁看?我觉得大概两类人:一是刚学完Python基础、打算往Web方向走的新手,需要一个能让你把知识串起来的完整框架;二是已经在用其他框架、对Django的“全家桶”风格感兴趣,想快速评估它适不适合自己项目的人。我会从“为什么Django这么设计”讲起,再手把手带你把一个博客项目从零搭出来,最后聊聊那些只有真正踩过坑才知道的细节。文章不吹概念,只讲实操,你跟着做完,就能真正理解Django的工作方式。

1. 思路拆解:Django到底凭什么被称为“瑞士军刀”

1.1 从设计哲学看Django:为什么要“全家桶”

我第一次接触Django的时候,也被它的“啥都管”震惊过。别的框架给你一个空壳,路由、模板、数据库操作都要你自己挑工具、拼装组合;Django不一样,它的核心哲学是“开箱即用”和“电池内置”。这两个词听起来玄乎,翻译成人话就是:官方已经帮你把最常用的Web开发组件都做好了,你只管在它搭好的骨架上填业务逻辑。

我举个例子你就明白了。比如用户登录功能,如果在Flask这种微框架里,你可能要自己写密码校验、session存储、登录状态判断,还得小心处理各种安全漏洞。但在Django里,用户表、密码加密、session机制、登录状态中间件,全都是内置的。你只要运行一次迁移命令,数据库里就会自动出现用户相关的表,再配一下登录URL和模板,一个可用的登录系统就出现了。这时候你再回头看“瑞士军刀”这个比喻,是不是有点懂了?它不是为了“全”而全,而是因为Web开发里大部分场景是重复的,把这些重复的事情标准化,开发效率才能提上来。

1.2 什么时候选Django,什么时候别选它

再说说Django的边界。瑞士军刀再全能,也不能当工兵铲用,框架选型同理。Django最适合的是“数据驱动型”的Web应用,比如内容管理系统、内部管理平台、电商网站后台、数据可视化大屏接口,这些场景涉及大量的增删改查、表格、权限、登录,用Django的Admin后台和ORM简直就是降维打击。

但如果你的项目主要是实时通信、超高并发的大流量接口服务,或者你的核心是一个逻辑简单的小微服务,Django那套完整结构反而显得重。这时候选个轻量框架会更舒服。我的建议很简单:如果你不确定选什么,而且做的是“带数据库的网站”,那Django基本不会让你后悔。它把你从一堆底层琐事里解放出来,让你把精力放在真正的业务上。如果你事情都还没搞明白,先学Django反而更稳妥,至少你不会被各种第三方库的兼容性逼疯。

2. 核心机制解析:先搞懂Django的三个核心部件

2.1 MVT架构到底在说什么

很多新手一上来就被MVC和MVT绕晕。Django官方叫它MVT:Model(模型)、View(视图)、Template(模板)。说白了,这就是一个“数据怎么来→逻辑怎么处理→页面怎么展示”的流水线。

Model负责跟数据库打交道,定义一个类就是定义一张表,类属性就是字段,完全不用手写SQL。View负责接收用户请求、取数据、做业务处理,然后把加工后的数据交给模板。Template负责展示,它就是一个带Django模板语法的HTML文件。注意,这里的View在传统MVC里其实相当于Controller的角色,名字不同而已,别被这个概念吓到。

我自己的理解是:MVT就是“让代码各管各的一段”。模板里不写业务逻辑,模型里不写页面展示,View作为中间人把两者连接起来。这样分工的好处是代码结构稳定,项目做大之后你也不会觉得乱。特别是团队协作的时候,新同事看一眼目录结构就知道去哪改东西。

2.2 ORM:把数据库操作变成“Python式思维”

ORM是Django最让我觉得省心的部分。它做的事情简单说就是:你不用再记MySQL的INSERT、UPDATE那些SQL语句,只需要用Python对象的语法去操作数据。

比如#创建一条新数据

Post.objects.create(title="你好", content="正文")

比如#查询标题里包含“你好”的数据

Post.objects.filter(title__contains="你好")

比如#按时间倒序取前10条

Post.objects.order_by("-created_at")[:10]

这种写法的好处有几个。第一,代码可读性高,读起来像人话;第二,你不用关心底层数据库是MySQL还是SQLite,切换数据库只需要改一下配置文件;第三,ORM自己会处理参数化查询,大量降低了SQL注入的风险。当然,ORM不能解决所有问题,后面你总会遇到需要手写SQL的场景,但在入门和开发效率上,它绝对是对新手最友好的部分。

2.3 Admin后台:为什么说它是“神器”

Django的Admin后台是我向所有人推荐Django的第一理由。它本质上是一个自动生成的、可登录的管理界面,你可以直接在浏览器里增删改查你定义的每一张数据表。只要你在admin.py里把模型注册进去,后台界面就自动出现了。

这个功能在日常开发中帮过我省大量时间。比如做一个活动报名系统,用户报名数据存到数据库了,你想看今天报了多少人、谁报了名、要不要人工修改某个人的信息——不用写一句代码,打开/admin页面就能操作。很多内部管理系统的原型,我就是靠Admin后台“拼”出来的,先把数据结构搭好,业务逻辑后补,后期还省了单独开发管理界面的功夫。这就是“瑞士军刀”里最能打的那把小刀。

3. 动手实操:从零建一个可运行的Django博客项目

3.1 环境准备与项目创建,注意别踩版本坑

实操前先说环境。我建议用Python 3.10及以上版本,Django用4.2 LTS或更高版本都可以,命令差别不大。第一件事是创建虚拟环境,这一步省了之后有你受的。不同项目的依赖互相干扰的时候,你会后悔当时图省事直接在全局环境里装包。

# 创建虚拟环境 python -m venv venv # 激活虚拟环境(Windows) venv\Scripts\activate # 激活虚拟环境(macOS/Linux) source venv/bin/activate

激活之后,命令行前面会多一个(venv)的提示,说明你已经进入了一个干净的Python世界。然后安装Django并创建项目。

pip install django django-admin startproject mysite cd mysite python manage.py startapp blog

我特别提醒一下:startproject后面那个名字“mysite”是项目配置所在目录的名字,startapp后面的“blog”才是你写业务代码的应用名。一个Django项目里可以塞多个应用,比如博客系统、留言板、用户中心可以分成三个应用,这本身就是Django推荐的组织方式。应用之间可以相对独立,后面维护起来思路清晰。

创建完之后,先用命令看看能不能跑起来。

python manage.py runserver

浏览器访问127.0.0.1:8000,如果看到了火箭发射的欢迎页,说明项目骨架已经成功了。这一步也顺带验证了环境没问题,方便后面排查。

3.2 配置 settings:语言、时区和应用注册

项目能跑起来了,但默认配置是英文页面,而且我们新建的blog应用还没被项目认领。打开mysite/settings.py,找到以下几项修改。

# 把我们的应用加进去 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', ... 'blog', # 新增这一行 ] # 改成中文界面 LANGUAGE_CODE = 'zh-hans' # 改成国内时区 TIME_ZONE = 'Asia/Shanghai'

这里解释一下INSTALLED_APPS。Django里每一样功能都是以“应用”为单位注册的,自带的admin、auth都是应用。你新写的blog应用不注册,Django就不知道它存在,后面的建表、页面路由也都不会生效。

至于TIME_ZONE,默认是UTC。如果你不改成Asia/Shanghai,将来模型里记录的时间会比北京时间少8个小时,排查问题时很让人抓狂。Django新版本默认USE_TZ=True,也就是数据库里存的是UTC标准时间。这个设计本意是好的,但新手在模板里直接输出时间时,很容易看到和本地时间不一致的结果。我的建议是:入门阶段先用默认的USE_TZ=True,只要时区配置正确,Django渲染模板时会自动转成当地时间的。真遇到麻烦,再考虑把USE_TZ改成False。

3.3 设计数据模型:博客文章表

现在开始写业务核心。打开blog/models.py,定义一个博客文章的数据模型。

from django.db import models class Post(models.Model): title = models.CharField(max_length=200, verbose_name="标题") content = models.TextField(verbose_name="正文") created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间") def __str__(self): return self.title

这里有三个字段类型,我给你捋一下:

  • CharField:定长字符串,适合标题、姓名这类内容,必须指定max_length。
  • TextField:长文本,适合正文,不限制长度。
  • DateTimeField:日期时间字段,auto_now_add会让它在这条数据创建时自动写入当前时间;auto_now则会在每次保存时自动更新成最新时间。

写完模型后,要把它变成数据库表,这一步就是Django的“迁移”。

python manage.py makemigrations blog python manage.py migrate

makemigrations是Django根据你写的模型“自动生成一段建表代码”,你可以理解成画了个施工图。migrate才是真正把施工图拿到数据库里去执行、把表建出来。很多新手只跑makemigrations,看到没报错就以为完成,其实数据表根本没创建,后面一访问就报“表不存在”。这两条命令是成对出现的,养成习惯:改完模型就依次执行。

3.4 注册Admin,快速看看数据

模型建好了,马上注册到Admin后台,体验一下那句“数据结构一搭,后台管理就有了”的感觉。

打开blog/admin.py,写入:

from django.contrib import admin from .models import Post admin.site.register(Post)

接着在终端里创建超级管理员账号:

python manage.py createsuperuser

按提示输入用户名、邮箱、密码。然后再次运行runserver,访问127.0.0.1:8000/admin,用刚才的账号登录,你就会看到一个可以增删改查Post数据的管理后台。直接在页面上点“增加”,添加一篇文章,保存后数据就进了数据库。在你还没写任何页面的时候,你的管理后台已经能用了,这个成就感会非常强。

3.5 写视图、配URL、做模板:让文章显示到页面上

后台加了几篇文章,接下来要把它们展示到网站首页。流程就是MVT三件套:先在View里写逻辑,需要查询文章列表并传到模板;再在模板里做一个列表页面;最后把请求的URL和View函数关联起来。

打开blog/views.py,写一个最简单的视图:

from django.shortcuts import render from .models import Post def post_list(request): posts = Post.objects.all().order_by('-created_at') return render(request, 'blog/post_list.html', {'posts': posts})

这里有两个关键点。第一,Post.objects.all()查询的是Post这张表的全部数据,order_by('-created_at')表示按创建时间倒序,最新的在最前面。第二,render这个函数负责把数据和模板拼接成最终HTML响应。字典里的键posts会在模板里直接用。

然后新建一个blog/urls.py文件,把URL视图路由写进去:

from django.urls import path from . import views urlpatterns = [ path('', views.post_list, name='post_list'), ]

注意这个urls.py需要你手动创建。再回到mysite/urls.py,把blog的urls包含进去:

from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('blog.urls')), ]

这段配置的意思是:请求“/”这个地址时,交给blog应用去处理。include是Django用来把多个应用的URL拼接在一起的工具,大项目就是靠它把每个模块的URL分隔开的。

最后做模板。在blog目录下创建templates/blog/post_list.html,内容简化一下:

<!DOCTYPE html> <html lang="zh-hans"> <head> <meta charset="UTF-8"> <title>我的博客</title> </head> <body> <h1>文章列表</h1> {% for post in posts %} <h2>{{ post.title }}</h2> <p>{{ post.content }}</p> <small>{{ post.created_at }}</small> <hr> {% empty %} <p>还没有文章,去后台添加一篇吧。</p> {% endfor %} </body> </html>

这里用到的{% for %}和{% empty %}就是Django模板语法。模板里只做循环、判断和输出变量,不做复杂计算。刷新浏览器首页,后台添加过的文章就会显示出来了。一个Django应用的“创建数据→管理数据→展示数据”闭环就算是完整走通了。

4. 常见问题与避坑指南:这些坑我替你踩过了

4.1 新手高频报错速查表

做开发不可能不报错,关键是报错后你得能看懂它。下面这些是我见过频率最高的几个,基本覆盖了新手两周内的主要困境。

报错信息常见原因解决办法
ModuleNotFoundError: No module named 'django'没进虚拟环境,或没安装Django检查命令行前是否有(venv),执行 pip install django
OperationalError: No such table: blog_post忘记执行 migrate执行 python manage.py migrate
ImproperlyConfigured: TemplateDoesNotExist模板文件路径不对确认模板放在应用下的templates目录里,文件名和视图里一致
NameError: name 'post_list' is not definedviews.py里函数名写错或没导入检查urls.py里的导入语句和函数名
CSRF verification failed表单里缺少CSRF令牌在
内加{% csrf_token %}
AttributeError: 'Post' object has no attribute 'post_list'视图函数和模型方法混了看清调用的对象到底是模型类的实例还是查询集
runserver 启动报端口被占用8000端口被其他程序占用使用 python manage.py runserver 8080 换端口

4.2 模板继承:为什么要早学早用

很多新手学模板,直接在文件里copy一份完整的HTML,然后到处粘贴。这个做法在页面一两个的时候问题不大,等页面多起来,改个页脚要挨个文件改,能改到你想骂人。Django的模板继承机制就是专门解决这个问题的。

先建一个base.html作为“母版”,放好公共的头和尾,在中间留一个block:

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>{% block title %}默认标题{% endblock %}</title> </head> <body> <nav>这里是导航栏</nav> {% block content %}{% endblock %} <footer>这里是页脚</footer> </body> </html>

然后在post_list.html里继承base.html:

{% extends "base.html" %} {% block title %}文章列表{% endblock %} {% block content %} <!-- 页面主体内容 --> {% endblock %}

这样每个子页面只需要写自己特有的那部分,公共结构全部集中在base.html里。我强烈建议从你第一次写模板就养成继承的习惯,哪怕只写一个页面也按这个套路来。等项目长了,你会感谢当初的自己。

4.3 关于时区和时间显示的个人经验

时区问题我前面已经提过了,这里再补充一个细节。Django新版本的USE_TZ默认是True,数据库存的是UTC时间。如果你在Admin后台看到的时间是正常的,那是因为Django做了转换;如果你在自定义模板里直接输出时间,偶尔看到的时间不对,多半就是时区问题。

如果你是一个纯新手,不想在这一块耗太多时间,我给你的建议很简单:

  • settings.py里TIME_ZONE设置为'Asia/Shanghai'。
  • 模板里显示时间时用Django的date过滤器,比如{{ post.created_at|date:"Y年m月d日 H:i" }}。
  • 数据库层面别手动去改时间字段,让auto_now_add和auto_now管理就好。

等你对Django更熟了,再回头研究UTC的来龙去脉也完全来得及。入门阶段,先把结果跑通最重要。

4.4 静态文件为什么全挂了

写点CSS、放张图片是迟早的事。新手最容易遇到的情况是:模板里写了{% load static %},引用了静态文件,结果浏览器显示全是404。

这个问题的根因在于Django对静态文件的处理逻辑:DEBUG=True时,runserver会自动为App自带的static目录提供文件服务;如果你把文件放到了项目的顶层static目录,则需要先告诉Django“静态文件都在哪”。在settings.py里这样配置:

STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / 'static', ]

然后在项目根目录创建一个static文件夹,把CSS、JS、图片放进去,模板开头加上:

{% load static %}

引用时写成:

<link rel="stylesheet" href="{% static 'css/style.css' %}">

如果你已经按上面的步骤做了,还是404,先检查文件在不在static目录里,再检查是不是手滑把static目录放到了blog应用下面而没放到项目根目录。总之,静态文件相关的坑大都是路径问题,没有太多玄学。

5. 进阶路线与学习心得:从“会跑”到“会设计”

5.1 Django学会了,下一步学什么

当你把本文的博客项目做完,你已经掌握了Django的骨架:MVT流程、ORM模型、URL配置、模板渲染、Admin后台。接下来可以根据你的目标选路线。

想做接口前后端分离的,学Django REST Framework(DRF)。它是Django生态里最核心的第三方库,专门用来自动生成API。学会了它,你的Django后端就可以给小程序、APP、前端页面提供JSON数据了。想做异步任务和定时任务的,学Celery,比如邮件发送、Excel导出这些耗时的操作,不适合让用户在线干等,丢给异步队列去处理是正经做法。想搞实时功能的,比如在线聊天、消息推送,学Channels,它让Django支持WebSocket。再往后是部署上线,学Gunicorn、Nginx以及云服务器的基本操作。

我的建议是:别急着一下子上全部。先把Django本身玩明白,做一个有完整业务逻辑的项目(比如带用户登录、文章增删改查、简单权限控制的管理系统),再根据你的实际业务需要接触DRF或者Celery。工具永远是跟着需求来的,没有需求硬学,学完不用,过两周就忘了。

5.2 我在实际操作中总结的几条心得

最后分享几个我自己的体会,不保证全对,但都是真金白银换来的。

第一,先跑通最小闭环,再美化细节。很多人学Django的时候,总想先配置一个特别完美的项目结构,或者先把模板样式调得漂漂亮亮。我的建议是反着来,优先把一个简陋但完整的流程跑通:建个模型,写个视图,显示在页面上。哪怕页面丑到没法看,但每个环节都通了,整个框架在你心里就串起来了。之后再加样式、加功能,都是增量修改,心态完全不一样。

第二,遇到报错,学会看Django的Debug页面。Django的调试页面是新手求助的信号灯。它会把报错位置、涉及的代码行、相关变量全部列出一个清爽的清单。很多人一看到红字就懵了,直接复制报错文本去搜索。其实先花两分钟读一眼页面,错误信息往往就在那里写着:哪一行的语法不对、哪个变量没定义,一目了然。调试页面顶部还有“SQL”“请求信息”“追踪”这些标签页,越早学会看它们,排查问题越快。

第三,代码要舍得重构。刚开始写的视图可能又长又乱,比如把所有业务逻辑全塞在一个函数里。这很正常,但你别留着不管。Django给了一个比较好的习惯:当某个视图超过几十行了,你要想一想能不能拆。比如表单验证提取成一个函数,数据统计逻辑挪到模型方法里,列表查询的逻辑抽到管理器里。重构不是没事找事,是为了让下次看代码的人(多半是你自己)少花时间。

第四,别怕看官方文档。很多中文教程博客写得不错,但细节更新往往不及时。Django每年都在小版本迭代,一些配置项的位置和默认值会变。遇到问题,去官方文档站搜索一下,正确率最高。英文不好没关系,配合翻译工具慢慢啃,看得多了就会熟。框架学习到最后,比拼的就是查文档和定位问题的能力,这个能力越早练越好。

说到底,Django这只“瑞士军刀”并不难掌握,难的是你想清楚要解决什么问题。先跟着这篇内容把项目跑起来,再去做一个自己想做的应用——那种在浏览器里看到自己写的东西被完整实现的感觉,就是Web开发最迷人的地方。希望这篇东西能成为你Django之旅的第一块垫脚石。

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

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

立即咨询