作者:IT策士
10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在公众号、今日头条持续发布最新文章,助你少走弯路。
无论你是刚跨入 Web 开发大门的新手,还是想从其他框架迁移过来的进阶开发者,理解 Django 的“骨架”和“灵魂”都是绕不开的第一步。本文不会只丢给你一堆命令和概念,而是通过环境搭建->Hello World->项目结构剖析->MTV 实战这一条线,部署和可亲手验证的例子,带你深入浅出地吃透 Django 的启动原理。
读完你会获得:
可运行的最小 Django 项目
对项目结构每个文件的清晰认知
通过控制台打印理解 Django 请求生命周期
MTV 模式下的模型建立、视图渲染、模板展示的全流程
1. 环境准备:搭建干净的 Python 舞台
1.1 确认 Python 版本
Django 4.2 LTS 需要 Python 3.8+,Django 5.0+ 要求 Python 3.10+。打开终端执行:
$ python3--versionPython3.12.3如果你的系统同时存在 Python 2,请始终使用python3和pip3命令。
1.2 创建虚拟环境
虚拟环境能隔离项目依赖,避免污染全局 Python。在项目父目录下:
$ python3-mvenv django_env $sourcedjango_env/bin/activate# Linux/macOS# 或 Windows 下: django_env\Scripts\activate激活成功后,终端提示符前会出现(django_env)标识。控制台输出类似:
(django_env)user@host:~/projects$1.3 安装 Django 并验证
(django_env)$ pipinstalldjango Collecting django Downloading Django-4.2.11-py3-none-any.whl(8.1MB)... Successfully installed asgiref-3.8.1 django-4.2.11 sqlparse-0.5.0(django_env)$ python-mdjango--version4.2.11看到版本号即为安装成功。至此环境准备完毕。
2. 第一个 Django 项目:从零到“火箭”
2.1 创建项目
使用django-admin startproject命令,我们创建一个名为mysite的项目:
(django_env)$ django-admin startproject mysite(django_env)$cdmysite(django_env)$lsmanage.py mysite/控制台没有任何输出是正常的—— Django 会默默生成一套初始文件。我们来看目录树:
mysite/ ├── manage.py └── mysite/ ├── __init__.py ├── settings.py ├── urls.py ├── asgi.py └── wsgi.py2.2 运行开发服务器,看见欢迎页
Django 自带轻量级开发服务器,绝对不要用于生产环境。执行:
(django_env)$ python manage.py runserver Watchingforfilechanges with StatReloader Performing system checks... System check identified no issues(0silenced). May13,2026-10:23:45 Django version4.2.11, using settings'mysite.settings'Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.打开浏览器访问http://127.0.0.1:8000/,你会看到 Django 的“小火箭”欢迎页。此时控制台会输出访问日志:
[13/May/202610:24:01]"GET / HTTP/1.1"20016364这个页面是django.views.debug默认提供的,说明项目骨架已能正常响应请求。在没有添加任何视图时,Django 的 URL 配置会引导到这个调试页面。
现在,我们要让它输出我们自己的 “Hello, World”。
3. 第一个应用与 Hello World:让控制台开口说话
Django 哲学是:一个“项目”可以包含多个“应用”。我们把业务逻辑放在应用里。
3.1 创建应用
(django_env)$ python manage.py startapp hello控制台同样无输出,但目录下多了一个hello/文件夹:
hello/ ├── __init__.py ├── admin.py ├── apps.py ├── migrations/ │ └── __init__.py ├── models.py ├── tests.py └── views.py3.2 编写视图:让函数返回文字,并向控制台打印
打开hello/views.py,写入:
from django.httpimportHttpResponse from datetimeimportdatetime def say_hello(request):# 这行会打印到运行服务器的终端上print(f"[{datetime.now()}] say_hello 视图被访问了!")returnHttpResponse("Hello, World! 你好,世界!")print正是我们观察请求时机的最直接方式。
3.3 配置 URL 映射
光有视图不行,必须告诉 Django 什么路径对应什么视图。在hello/目录下新建urls.py:
from django.urlsimportpath from.importviews urlpatterns=[path('', views.say_hello,name='hello'),]然后修改项目总路由mysite/urls.py,将hello应用的路由包含进来:
from django.contribimportadmin from django.urlsimportpath, include urlpatterns=[path('admin/', admin.site.urls), path('hello/', include('hello.urls')),# 新增]3.4 注册应用(重要)
Django 需要知道有哪些应用,这样它才能找到模板、静态文件等。编辑mysite/settings.py,在INSTALLED_APPS列表中添加:
INSTALLED_APPS=['django.contrib.admin','django.contrib.auth',...'hello',# 注册我们的应用]3.5 启动服务器,见证 Hello World
重新运行服务器(如果之前没停,它会自动重载):
(django_env)$ python manage.py runserver浏览器访问http://127.0.0.1:8000/hello/,页面显示:
同时,控制台会打印:
[2026-05-1310:30:15]say_hello 视图被访问了![13/May/202610:30:15]"GET /hello/ HTTP/1.1"20030进阶点:这里的
logging模块。
这样,我们就有了第一个会说话的 Hello World。更重要的是,你看到了请求 → 路由 → 视图的链路,控制台打印就是这链路的心跳。
4. 项目结构深度解剖:每个文件都在干什么?
新手往往会被一堆.py文件吓到,下面我们把它们拆开揉碎。结合“初始化 + 运行”的控制台输出,你会理解每个文件的存在意义。
4.1manage.py:项目的管家
$catmanage.py#!/usr/bin/env python"""Django's command-line utility for administrative tasks.""" import os import sys def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')try: from django.core.managementimportexecute_from_command_line except ImportError as exc: raise ImportError(...)execute_from_command_line(sys.argv)它做的事:设置环境变量DJANGO_SETTINGS_MODULE,指向mysite.settings,然后把命令行参数交给 Django 的命令执行器。我们常用的runserver、startapp、migrate、shell都是由此进入。
你运行的python manage.py runserver之所以能启动服务器,就是因为它加载了mysite.settings中的配置(包括已安装应用、中间件等)。
4.2 项目配置包mysite/
__init__.py
空文件,告诉 Python 这个目录是一个包。通常不需要动它。
settings.py—— 项目的控制中心
打开这个文件,关键部分:
BASE_DIR=Path(__file__).resolve().parent.parent# 项目根目录SECRET_KEY='django-insecure-xxxx'# 密钥,加密签名用,绝对要保密DEBUG=True# 开发模式,提供详细错误页面,生产环境必须 FalseALLOWED_HOSTS=[]# 允许访问的主机名,生产需配置INSTALLED_APPS=[...]# 所有安装的应用MIDDLEWARE=[...]# 中间件栈,处理请求/响应的钩子ROOT_URLCONF='mysite.urls'# 根 URL 配置TEMPLATES=[...]# 模板引擎配置DATABASES={'default':{'ENGINE':'django.db.backends.sqlite3',...}}# 数据库控制台相关:当你运行runserver时,终端会输出:
Django version4.2.11, using settings'mysite.settings'这印证了manage.py所设的环境变量。
urls.py—— 请求的交通指挥
前文我们已经修改过它。初始内容通常只有admin/路由。每个path()将 URL 模式映射到一个视图函数。这里的“include”机制允许层层分发,形成树状路由结构,特别适合大型项目。
wsgi.py和asgi.py—— 通往生产环境的门
WSGI(Web Server Gateway Interface):同步接口,传统部署使用(如 Gunicorn + Nginx)。
ASGI(Asynchronous Server Gateway Interface):异步接口,支持 WebSocket、长连接。
我们使用的runserver开发服务器,其实就是启动了一个简单的 WSGI(或 ASGI)服务器。你可以通过python manage.py runserver的控制台输出看到协议类型(默认 WSGI,如果安装了异步支持可能切换)。通常这些文件不需要改动,除非要自定义应用加载。
4.3 应用结构hello/
每个应用是一个可复用的模块:
views.py:存放视图函数或类,处理请求并返回响应。我们已经在这里放了say_hello。models.py:定义数据模型(表结构),这是我们接下来要玩的重点。admin.py:注册模型到 Django 自带的管理后台。apps.py:应用配置,可在settings的INSTALLED_APPS中使用'hello.apps.HelloConfig'这种完整的路径。migrations/:存放数据库迁移文件。每当你修改模型并执行makemigrations,Django 会在这里生成 Python 脚本,记录数据库变更。tests.py:单元测试。建议一写应用就写好测试。
理解了结构,我们就可以深入 MTV 模式,让程序不只是返回字符串,而是动态地从数据库取数据并渲染漂亮页面。
5. MTV 模式深入剖析:模型、模板、视图的协奏曲
Django 常被归类为“MVC”框架,但它自己称为MTV:
Model:数据存取层,处理数据库和业务规则。
Template:表现层,决定数据如何展示。
View:业务逻辑层,接收请求,处理数据,调用模板返回响应。
URL 分发器不属于 MTV 字母,但同样重要:它把 URL 映射给 View。我们通过一个完整的例子来体现:创建一个博客帖子,在视图里查询并打印,然后显示在模板中。
5.1 创建 Post 模型
编辑hello/models.py:
from django.dbimportmodels class Post(models.Model): title=models.CharField(max_length=100)content=models.TextField()created_at=models.DateTimeField(auto_now_add=True)def __str__(self):returnself.title我们定义了一个Post表,有标题、正文和自动添加的创建时间。
5.2 生成并执行迁移,观察控制台
迁移是 Django 的“时光机”,能安全地变更数据库结构。首先生成迁移文件:
(django_env)$ python manage.py makemigrations hello Migrationsfor'hello':hello/migrations/0001_initial.py - Create model Post控制台会告诉我们生成了0001_initial.py,并简述它做了什么。你可以通过sqlmigrate查看对应的 SQL 语句(这里展示输出):
(django_env)$ python manage.py sqlmigrate hello 0001 BEGIN;-- -- Create model Post -- CREATE TABLE"hello_post"("id"integer NOT NULL PRIMARY KEY AUTOINCREMENT,"title"varchar(100)NOT NULL,"content"text NOT NULL,"created_at"datetime NOT NULL);COMMIT;新手注意:sqlmigrate并不执行迁移,只是打印 SQL,帮助我们验证。实际应用到数据库要执行migrate:
(django_env)$ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, hello, sessions Running migrations: Applying hello.0001_initial... OK终端清晰地显示了应用的迁移名称和状态OK。现在数据库里已经有了hello_post表。
5.3 用 Django shell 玩转模型 —— 控制台输出的绝佳示例
Django 提供了一个增强版 Python 交互环境,自动加载项目设置和模型:
(django_env)$ python manage.py shell进入后,我们可以随心所欲地操作模型,所有输出直观可见:
>>>from hello.modelsimportPost>>># 创建两条帖子>>>p1=Post.objects.create(title="Django 入门",content="MTV 模式很容易理解")>>>p2=Post.objects.create(title="Python 之美",content="简洁优雅,强大无比")>>>>>># 查询所有帖子>>>posts=Post.objects.all()>>>print(posts)<QuerySet[<Post: Django 入门>,<Post: Python 之美>]>>>>>>># 过滤查询>>>p=Post.objects.get(id=1)>>>print(p.title, p.created_at)Django 入门2026-05-1310:40:22.123456>>>>>># 修改和保存>>>p.content="MTV 模式真的很容易理解!">>>p.save()>>>>>># 链式查询打印>>>forpostinPost.objects.filter(title__contains='Django'):... print(f"帖子:{post.title},创建于 {post.created_at}")... 帖子:Django 入门,创建于2026-05-1310:40:22.123456>>>>>>exit()shell 的输出就是最好的老师。你可以在真正写视图之前,先用 shell 验证查询逻辑,观察返回的数据结构,确保思路正确。
5.4 编写视图:查询数据并添加控制台日志
更新hello/views.py,加入显示帖子列表的视图:
from django.shortcutsimportrender from django.httpimportHttpResponse from datetimeimportdatetime from .modelsimportPost def say_hello(request): print(f"[{datetime.now()}] say_hello 视图被访问了!")returnHttpResponse("Hello, World! 你好,世界!")def post_list(request):# 从数据库取回所有帖子posts=Post.objects.all().order_by('-created_at')print(f"[{datetime.now()}] 查询到 {len(posts)} 条帖子")# 控制台日志# 传递数据给模板渲染returnrender(request,'hello/post_list.html',{'posts':posts})5.5 创建模板:让数据穿上 HTML 的外衣
在hello/目录下创建templates/hello/两级目录(命名空间约定:应用名/模板名),新建post_list.html:
<!DOCTYPE html><html><head><metacharset="utf-8"><title>博客列表</title></head><body><h1>帖子列表</h1><ahref="/hello/">返回 Hello</a><hr>{%forpostinposts %}<divstyle="margin-bottom:20px;"><h2>{{post.title}}</h2><small>{{post.created_at|date:"Y-m-d H:i"}}</small><p>{{post.content|truncatewords:30}}</p></div>{% empty %}<p>还没有帖子。</p>{% endfor %}</body></html>这里出现了 Django 模板语法:
{% for post in posts %}循环{{ post.title }}变量输出|date和|truncatewords过滤器
5.6 添加 URL 映射
编辑hello/urls.py,增加新路由:
urlpatterns=[path('', views.say_hello,name='hello'), path('posts/', views.post_list,name='post_list'),]现在访问http://127.0.0.1:8000/hello/posts/,你会看到一个帖子列表页面。同时控制台输出:
[2026-05-1310:45:01]查询到2条帖子[13/May/202610:45:01]"GET /hello/posts/ HTTP/1.1"200512如果我们在 shell 中再多创建几条帖子,页面会动态更新,控制台日志也会随之变化。这就是 MTV 模式的完整协作:
浏览器发起请求
URL 配置匹配到
post_list视图视图调用Model(
Post.objects.all()) 从数据库获取数据视图将数据包装为上下文字典
视图调用
render()选择Template渲染出 HTML返回响应给浏览器
5.7 进阶调试:在视图中打印请求详情
对于进阶开发者,理解请求对象能帮助我们排错和扩展功能。在post_list视图中添加更详细的日志:
def post_list(request): print("="*40)print(f"请求路径: {request.path}")print(f"请求方法: {request.method}")print(f"GET 参数: {request.GET}")print(f"用户: {request.user}")print(f"User-Agent: {request.META.get('HTTP_USER_AGENT')}")posts=Post.objects.all().order_by('-created_at')print(f"查询到帖子数: {posts.count()}")print("="*40)returnrender(request,'hello/post_list.html',{'posts':posts})访问页面后,控制台输出:
========================================请求路径: /hello/posts/ 请求方法: GET GET 参数:<QueryDict:{}>用户: AnonymousUser User-Agent: Mozilla/5.0(Macintosh;Intel Mac OS X 10_15_7)... 查询到帖子数:2========================================甚至你可以尝试带参数访问:http://127.0.0.1:8000/hello/posts/?debug=true,控制台就会显示GET 参数: <QueryDict: {'debug': ['true']}>。这对于理解中间件、用户认证和请求流非常有益。
6. MTV 模式 vs MVC 的误解,及 Django 的“智能”调度
很多人刚学 Django 时会听到 “Django 是 MVC 框架”,但官方文档称它为 MTV。其实对应关系很简单:
Django 把“控制器”的部分逻辑分散给了框架自身的 URL 分发器和视图函数。因此,Django 视图更像一个控制器,而模板才是真正的“视图”。只要记住:视图选择并返回数据,模板渲染数据,这个弯就转过来了。
Django 的请求处理流程(从新手到进阶都应印在脑子里):
浏览器 → Nginx/WSGI → Django 中间件栈 → URL 路由匹配 → 视图函数(可调用模型)→ 加载模板 → 渲染 → HTTP 响应 → 中间件栈反向处理 → 返回浏览器开发服务器runserver帮我们简化了前面的环节,但中间件、路由、视图这一套逻辑始终一致。
7. 更多控制台输出实例:感知 Django 的生命周期
7.1 观察 SQL 日志
在settings.py中,可以添加日志配置,让所有数据库查询打印到控制台:
LOGGING={'version':1,'handlers':{'console':{'class':'logging.StreamHandler',},},'loggers':{'django.db.backends':{'handlers':['console'],'level':'DEBUG',},},}重启服务器,再次访问帖子列表页,控制台会多出:
(0.001)SELECT"hello_post"."id","hello_post"."title",... FROM"hello_post"ORDER BY"hello_post"."created_at"DESC;args=()这能帮助我们分析 N+1 查询问题,是进阶优化的必备技能。
7.2 利用manage.py shell_plus(需安装 django-extensions)
进阶用户推荐安装django-extensions,其提供的shell_plus会自动导入所有模型,并支持自动补全:
$ pipinstalldjango-extensions $# 在 settings.py INSTALLED_APPS 添加 'django_extensions'$ python manage.py shell_plus# Shell Plus Model Imports...from hello.modelsimportPost...>>>Post.objects.create(title='快速测试',content='自动导入超方便')<Post: 快速测试>输出会列出所有自动导入的模块,让你能立刻开始操作。
8. 结语:从 Hello World 到掌控全局
通过这篇文章,你不仅得到了一个可运行的 Django 环境,更亲手搭建了一个包含控制台日志、数据库查询、模板渲染的 MTV 完整示例。我们从“环境搭建”开始,用django-admin startproject和startapp命令搭起骨架;利用runserver和print在终端观察请求动态;深度剖析每个文件职责;最终在 MTV 模式下,用 Model + View + Template 实现了动态帖子列表。
给新手的建议:不要跳过控制台输出。每当迷惑时,就在视图里加一行print(request.__dict__)或查看 SQL 日志。Django 的透明性是它的优点,控制台就是你的解剖台。
给进阶者的提醒:你已看到 MTV 的完整链路,可以进一步尝试中间件编程、类视图、基于类的通用视图,甚至深入研究 ASGI 异步视图。但无论技术栈如何变迁,理解请求如何流经项目结构,始终是解决问题的基础。
Django 的第一声 “Hello, World” 只是开始,愿你在接下来的开发中,每一个print都能为你照亮前行的路。还可以去公众号、今日头条搜索「IT策士」,一起升级 IT 思维 !