很多人第一次接触Django,最容易卡住的其实不是写代码,而是装完环境之后站在一堆陌生文件前面发呆:settings.py、urls.py、manage.py……每个文件看起来都有事,又不知道谁负责什么。我见过不少同事,项目从django-admin startproject开始,到runserver报错退场,整个过程都没超过十分钟。
所以这次我打算把“从配置到运行”这条线完整串一遍。不是教你怎么背命令,而是把每一步背后的逻辑讲清楚——环境为什么要这么搭、配置文件里每个开关到底在管什么、数据库是怎么“零配置”跑起来的、以及你敲下runserver之后,Django 在背后到底做了哪些事。这篇适合完全没接触过 Django 的纯新手,也适合那种“能跑但说不清原理”的人。
1. 搭建独立运行环境:为什么每个项目都要自己的“虚拟厨房”
1.1 先选对 Python 版本,再谈安装
开始之前,建议你先确认本机的 Python 版本。我通常要求 3.10 以上,越新越好。Django 对 Python 版本有明确的下限要求,如果你装的是老版本 Python,后续可能连pip install django都过不去,或者装上了也跑不起来,报一些莫名其妙的语法错误。
检查版本的方式很简单:
python --versionWindows 用户如果直接敲python无效,可以试试py --version。这个细节很多人吃亏:命令行里认不到python,不代表你没装 Python,只是可执行程序没注册到 PATH 里,用py这个启动器就能绕过去。
1.2 创建虚拟环境并激活
我强烈建议你永远不要在全局环境里直接pip install django。原因我后面细说,先看命令。在项目根目录下执行:
python -m venv .venv这会生成一个.venv文件夹,里面是一套独立的 Python 解释器和 pip 环境。接下来要“激活”它:
- Windows PowerShell:
.venv\Scripts\Activate.ps1 - macOS / Linux:
source .venv/bin/activate
激活之后,你会注意到命令行提示符前面多了一个(.venv),这说明你已经在虚拟环境里了。这时候再用 pip 安装的包,只会进到这个.venv里,跟外面的系统环境彻底隔开。
1.3 为什么不推荐直接装在全局环境
我见过太多次这样的场景:某台开发机上装了几十个项目,每个项目依赖的 Django 版本不一样,有的项目要 2.2,有的要 4.2,还有一堆第三方库互相打架。pip 默认是“覆盖式”安装,后装的高版本会直接把旧版本顶掉,于是老项目某天突然启动不了了。
虚拟环境相当于给每个项目单独准备了一套厨房,调料、锅具、灶台都是自己的,互不串味。哪怕你在 A 项目里把 Django 升级到最新版,B 项目里那个老版本也纹丝不动。这个习惯越早养成越好,别等项目多了再回头补课。
1.4 安装 Django 并锁定版本
激活虚拟环境之后,安装 Django:
pip install django==4.2.16为什么要手动指定版本?因为 Django 的大版本之间,配置写法、默认行为、第三方库兼容性差异很大。比如 Django 3.x 和 4.x 的url写法就有区别,5.x 对 Python 版本要求更高。如果你直接pip install django,装到的是当前最新版,但网上大量教程写的是 3.x 或 4.x 的写法,照抄很容易踩坑。
我个人推荐从 4.2 这个长期支持版本入门,而不是追最新大版本。原因很简单:LTS 版本维护周期长,资料多,第三方生态适配成熟,遇到问题搜解决方案最方便。
安装完验证一下:
python -m django --version看到版本号输出,环境这一关就算过了。
2. startproject 生成的项目骨架:每个文件的来头与职责
2.1 命令里的“点号”到底意味着什么
进入项目目录,执行:
django-admin startproject config .注意最后这个点号,很多人容易忽略它。它的意思是在当前目录直接生成项目文件,不再额外套一层目录。
如果你漏写这个点,执行startproject config,Django 会创建一个config文件夹,并在config里再套一层config,最终目录层次变成config/config/,启动时还容易因为路径问题找不到配置。新手包里最常见的运行失败,有一半是这个原因。
2.2 生成的文件逐个拆解
命令执行完后,当前目录下会多出这些东西:
config/ __init__.py settings.py urls.py asgi.py wsgi.py manage.py按我的习惯,把每个文件负责的事列成一张表,比反复翻文档管用得多:
| 文件 | 职责 |
|---|---|
manage.py | 命令行工具入口。runserver、migrate、startapp等操作都靠它转发命令 |
config/__init__.py | 让config目录成为一个 Python 包 |
config/settings.py | 项目的总配置中心,数据库、应用、中间件、模板、时区全在这里 |
config/urls.py | URL 路由表,决定浏览器访问哪个地址时,由哪段代码响应 |
config/asgi.py | 异步服务入口,跑异步接口或某些部署方式时使用 |
config/wsgi.py | 同步服务入口,生产环境常用的gunicorn等工具需要它 |
其实前三个文件是你日常打交道最多的,asgi.py和wsgi.py前期基本不用动。
2.3 Project 和 App 的概念区别
这里必须花两分钟说清楚一个概念,因为后面所有内容都建立在这上面。
Django 里,Project 是整站,它管的是全局配置:装哪些应用、用什么数据库、URL 怎么分发。App 是功能模块,比如一个博客系统里有文章模块、评论模块、用户模块,每个模块可以拆成一个 app。
Project 是一个完整的“容器”,App 是容器里的“服务单元”。一个 Project 可以包含多个 App,一个 App 也可以被多个 Project 复用。有人把 Project 比作房子的主体结构,App 比作房间里的家具电器,我觉得挺贴切。
这篇我们先不创建 App,目的就是先把框架本身跑起来,理解 Project 层面是怎么回事。
3. settings.py 逐项拆解:真正的配置工作从读懂总控台开始
3.1 安全三兄弟:SECRET_KEY、DEBUG、ALLOWED_HOSTS
打开config/settings.py,前几个变量就够你琢磨一阵子了。
SECRET_KEY是 Django 的签名密钥,会话、密码重置、CSRF 校验等一堆安全机制都依赖它。这个值绝对不能泄露,更不能传到公开的代码仓库里。开发阶段无所谓,以后部署时一定要改成环境变量注入的方式。
紧跟着的DEBUG = True是开发模式下的调试开关。它的作用是:页面报错时直接把完整的异常堆栈渲染在浏览器里,包括具体到哪一行代码出错。这对开发期排查问题极其友好。
但是你要记住:DEBUG = False之后,Django 不再帮你处理静态文件,而且你必须配置ALLOWED_HOSTS,否则直接给你一个 400 Bad Request。这俩是联动的。很多人部署时第一步就把DEBUG改成False,结果页面全挂了,其实就是没理解这个关联。
3.2 已安装应用与中间件:框架默认配好的骨架
往下看,INSTALLED_APPS里默认有这些:
django.contrib.admin:自带的后台管理界面django.contrib.auth:用户认证体系django.contrib.contenttypes:内容类型框架,权限和 admin 的底层依赖django.contrib.sessions:会话机制django.contrib.messages:临时消息提示django.contrib.staticfiles:静态文件管理
很多新手一看这里就慌了:我啥还没写呢,你装这么多东西干啥?其实这些是 Django 的“标准厨房配菜”,它们和后面的MIDDLEWARE、数据库迁移是配套的。比如sessions要配合会话中间件,auth要配合认证中间件,游戏规则是爹妈都帮你定好了,你暂时不用动。
MIDDLEWARE列表则会按顺序处理每一个请求。我习惯把它理解成一条快递分拣流水线:请求进来后,要过一个又一个站点,每个站点只检查自己那部分事。比如安全中间件检查请求头,会话中间件加载 session,认证中间件绑定当前用户。顺序很重要,尤其SessionMiddleware必须放在AuthenticationMiddleware前面,因为认证要依赖会话先取到用户。
3.3 模板、路由、数据库与静态文件:偏业务侧的默认配置
ROOT_URLCONF = 'config.urls'这行,是让 Django 知道“路由表在哪个文件”。你以后学多项目部署时,每个项目的 URLconf 是独立的。
TEMPLATES是一个列表,里面配置模板引擎、模板目录、上下文处理器。默认的配置适合绝大多数场景,你暂时只需要知道:它负责在“返回 HTML 页面”的时候,去哪找模板文件、渲染时默认注入哪些变量。
DATABASES默认长这样:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }这配置的意思是:用自带 SQLite 数据库,数据库文件就生成在项目根目录下,叫db.sqlite3。这个我们下一节重点讲。
往下还有几个容易被忽略但很常见的坑:
LANGUAGE_CODE = 'en-us',TIME_ZONE = 'UTC'。如果你不改成中文和北京时间,后面 admin 后台界面是英文的,时间还会差八个小时。我的习惯是:
LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_TZ = True这里要特别解释一下USE_TZ = True的副作用:开启后,Django 存数据库的时间永远是 UTC 时间,页面展示时再按TIME_ZONE转换成本地时间。也就是说,你只改了TIME_ZONE而不改USE_TZ,直接查数据库时看到的还是 UTC,容易误以为“时间没改过来”。这是新手极容易困惑的点。
STATIC_URL = 'static/'是静态文件 URL 前缀,CSS、JS、图片文件访问路径都从它出发。开发模式下不用额外处理,部署时需要配合whitenoise或反向代理。
看完这一节,你应该已经意识到一件事:配置文件里没有“晦涩难懂”的东西,只有你没查过文档的东西。每个变量都在回答一个具体问题,只是没人把它们串起来讲。
4. 数据库“零配置”起步:SQLite 与迁移命令的配合逻辑
4.1 为什么默认数据库是 SQLite
刚接触 Django 的人经常问:我是不是得装个 MySQL 或者 PostgreSQL 才能跑起来?
不用。Django 默认的 SQLite 是一个嵌入式数据库,整个数据库就是一个文件,不需要额外安装服务,不需要账号密码,也不需要监听端口。开发阶段用它极其合适,因为你大部分时间在调试逻辑,而不是压测性能。
类比一下:SQLite 就像你自己工位上的记事本,MySQL 和 PostgreSQL 像公司文档管理系统。记事本在自己桌上用方便,但多人协作、并发写入、海量查询时就不顶用了。所以开发期用 SQLite 起步没问题,部署上线时再切换到 PostgreSQL 是更稳妥的做法。
4.2 migrate 到底迁移了什么
配置完成之后,执行:
python manage.py migrate你会看到一串Applying ... OK的输出。这个命令做的事是:把INSTALLED_APPS里那些内置应用的表建到db.sqlite3里。比如auth应用的用户表,sessions应用的会话表,admin应用的操作记录表。
这里要讲清楚一个核心概念:migration 是模型变化的版本记录,不是一次性建表脚本。
Django 里,模型类定义在 app 的models.py中。当你修改模型后,通过python manage.py makemigrations生成一个迁移文件,这个文件记录了“模型从上一个版本变成了什么”。然后执行python manage.py migrate,Django 会去查django_migrations表,看哪条迁移记录还没执行过,按顺序补执行。
所以你会发现:migrate重复执行一百次也不会重复建表,因为每一条迁移执行过后都会被登记。这个机制保证了多环境同步时,不会有人漏掉一次变更。
你可以打开数据库看看建了哪些表。用命令:
python manage.py dbshell然后输入.tables查看表列表,输入.quit退出。这种方式不依赖任何第三方数据库工具,日常查数据很方便。
4.3 顺手创建一个后台管理账号
Django 自带那个 admin 后台,不创建账号是进不去的。执行:
python manage.py createsuperuser按提示输入用户名、邮箱、密码,之后启动服务,访问http://127.0.0.1:8000/admin/,就能用刚创建的账号登录。
这个后台在你后续开发 app、注册模型之后会非常有用——CRUD 操作界面化,很多临时数据维护根本不用写代码。现在先知道有这回事就行。
5. 让第一个请求真正跑通:URLconf、视图函数与浏览器之间的链路
5.1 runserver 启动前后的机制
现在执行:
python manage.py runserver看到Starting development server at http://127.0.0.1:8000/这行输出,说明服务已经起来了。默认绑定的是127.0.0.1:8000,只能本机访问。想让局域网内其他设备也能访问,改成:
python manage.py runserver 0.0.0.0:8000这个命令会让 Django 监听所有本机网络接口,同事手机和电脑就能通过你的局域网 IP 访问了。
还有一点必须知道:开发服务器带着自动重载机制。你改了.py文件,它会自动检测到变化并重启。但新增了一些特殊目录或配置文件时,它有时反应不过来,这时候手动 Ctrl+C 再启动一遍最省心。
另外,这个开发服务器是按单进程跑的,并发能力远不如生产部署方式。它能帮你快速调试业务逻辑,但别拿它当生产服务器扛流量。
5.2 写一个最简视图并配好路由
打开config/urls.py,默认内容只有 admin 的路由。我们做一件小事,让首页有反应。
在config目录下新建一个views.py,写入:
from django.http import HttpResponse def index(request): return HttpResponse("你好,Django 跑通了!")然后把urls.py改成:
from django.contrib import admin from django.urls import path from config import views urlpatterns = [ path('', views.index), path('admin/', admin.site.urls), ]刷新浏览器访问http://127.0.0.1:8000/,你应该能看到那段中文文本。
这里我说明一下:我选择把视图函数放在config/views.py,只是为了演示方便。后面你创建了真正的 app,视图应该放在 app 自己的views.py里。现在这样写是为了把链路打通,别在“文件该放哪”这种问题上纠结太久。
5.3 请求的完整链路:从 URL 到响应的每一步
这个过程值得仔仔细细走一遍,因为整个 Django 的生命周期就是这段路的循环:
浏览器发出请求GET /,Django 先根据ROOT_URLCONF找到config/urls.py,把这个文件里的urlpatterns当成一张路由表,从上到下匹配请求路径。匹配到path('', views.index)后,调用views.index(request)这个函数。函数执行完返回一个HttpResponse对象,Django 再把它封装成 HTTP 响应,传回给浏览器。
这里面最核心的认知是:视图函数只负责接收请求、返回响应,不负责思考“路由怎么匹配”。路由匹配是 URLconf 的事,业务处理是视图函数的事,两者分开,各管一摊。
你可以在这条链路上做几个小实验,加深印象:
- 访问一个不存在的路径,比如
/abc/,在DEBUG = True时你会看到一个漂亮的 404 调试页面,明确告诉你哪个路由规则被尝试过、为什么没匹配上。 - 把
urls.py里加一行path('hello/', views.index),访问/hello/,你会发现同一个视图函数可以对应多个 URL。
这两个小实验做完,你对“路由表”的理解会比读十遍文档都深刻。
6. 运行期高频坑:端口占用、时间差、404 与改完不生效的排查清单
6.1 现象与原因对照表
我把自己和身边人踩过的坑汇总了一张表,遇到对应现象直接查原因:
| 现象 | 常见原因 | 解决办法 |
|---|---|---|
| 提示端口 8000 已被占用 | 上次启动没关干净 | 换端口跑:python manage.py runserver 8080,或杀掉占用进程 |
| 数据库表没建出来 | 还没执行 migrate | 直接执行python manage.py migrate |
| 创建超级用户报错 | 表尚未迁移 | 先迁移再创建,顺序不能反 |
| 修改代码后页面没变化 | 自动重载没触发 | 手动 Ctrl+C 重启 runserver |
| 访问返回 400 Bad Request | DEBUG=False且ALLOWED_HOSTS没配好 | 把域名或 IP 加进ALLOWED_HOSTS |
| 时间显示差 8 小时 | 时区配置和 USE_TZ 的联动没搞清 | 检查TIME_ZONE与USE_TZ组合 |
django-admin命令找不到 | 虚拟环境没激活 | 先激活.venv再执行命令 |
6.2 环境与命令层面的三个典型坑
第一个坑:装了 Django 但django-admin提示不存在。九成情况是你没激活虚拟环境。检查方式很简单——命令行前面有没有(.venv)前缀。如果没有,激活之后一切恢复正常。
第二个坑:Windows 下pip命令报红。不要慌着重装 Python。如果你同时装了多个 Python 版本,用python -m pip这种形式,可以明确指定用哪个解释器执行命令,比单独敲pip更可控。
第三个坑:数据库文件被误删。SQLite 的数据全在db.sqlite3这个文件里,如果你把它删了,所有迁移记录和业务数据都没了。有些人不知道这一点,随手清空了文件,重启项目后看到“一堆表不存在”,还以为是程序坏了。其实重新执行一次migrate就能重建表,但数据是找不回来的。
6.3 配置层面的安全习惯与版本控制建议
配置上最需要养成的好习惯,是把SECRET_KEY和数据库文件从代码仓库里剔除出去。在项目根目录建一个.gitignore,至少写上这几行:
.venv/ db.sqlite3 __pycache__/ *.pyc staticfiles/这样做的好处很明显:密钥不会随着代码仓库共享出去,数据库文件不会因为测试操作反复冲突。我见过不止一个团队因为把db.sqlite3提交进仓库,导致同事 pull 下来后数据库互相覆盖,排错排了一下午。
如果非要给一个顺序建议,我建议你按这条主线走:先跑通默认页面,再写最简视图,再搞清楚迁移机制,最后再回头逐行阅读 settings.py。从上到下把配置啃一遍看着很笨,但对后来的调试能力帮助很大。Django 的“配置到运行”看似琐碎,真正跑通之后,你得到的不仅是一个启动成功的项目,更是一张完整的请求处理地图。后续不管是加 App、建模型、接数据库还是上线部署,都是在这张地图上继续添路标而已。