刚接到一个新项目的时候很多人习惯直接django-admin startproject一把梭然后python manage.py runserver看到欢迎页就以为初始化完成了。我在帮模拟项目X搭后台的时候也走过这条路后来发现初始化阶段的每个决定几乎都会影响后面几个月的开发节奏。所以这篇就围绕 Django 项目的建立与初始化把版本选型、虚拟环境、配置管理、数据库方案、用户模型这些前置决策一次性聊透顺便把我踩过的坑和排查思路一起交代清楚。这个流程适合两类人刚接触 Django 的新手需要理解初始化不只是跑起来已经写过几个项目但一直用默认配置走天下的老手我保证后面有好几条坑你们也见过。核心的价值在于把初始化阶段该做的前置决策补齐让后续开发不再为早期偷懒买单。1. 初始化前的核心决策版本、工具与项目规划1.1 Python、Django 与虚拟环境怎么选先讲版本选择。Django 的版本策略比较激进小版本升级频繁但真正适合生产的是 LTS 版本。我在新项目里一般优先选当前在维护的 LTS比如 Django 4.2 或者 5.2它们都有较长的安全维护期不会出现项目写到一半框架突然不再维护的情况。Python 版本则要和 Django 版本匹配Django 5.x 要求 Python 3.10 以上我习惯用 3.12 或 3.13既能吃到新语法兼容性也稳。这里必须说一句不要图省事用系统自带的 Python 直接装依赖后端项目依赖隔离这件事越早做越好。虚拟环境工具我推荐用 Python 自带的venv它是标准库的一部分不需要额外安装足够满足绝大多数项目需求。virtualenv和conda也有自己的适用场景但venv胜在简单直接创建和激活方式在 Windows、Linux、macOS 上差异很小团队协作时命令可以完全统一。至于更上层的poetry、pipenv、uv这类工具它们解决的是依赖管理和构建流程的问题适合对工程质量要求更高的团队。初始化阶段用venv先把隔离做好后续迁移成本很低。为什么一定要隔离环境一个很朴素的道理是项目A用了 Django 4.2项目B用了 Django 5.2如果不隔离两个版本会在全局环境里互相覆盖轻则版本错乱重则项目根本跑不起来。我还遇到过系统里的 Python 环境被某个项目塞满了一堆旧依赖导致新项目装包时反复出现版本冲突的情况。所以项目环境独立这件事从第一天就要立住不要等出了问题再后悔。1.2 应用拆分与项目目录结构初始化阶段的目录结构直接体现你对项目的理解。很多官方教程喜欢建一个项目目录再套一个配置目录实际项目里我更推荐用django-admin startproject config .这种写法把项目配置统一放在config目录下业务代码根据功能拆成不同的 app。为什么不用项目名直接作为配置目录因为当你的项目名和你新建的 app 重名或者在别的模块里 import 时会出现命名空间冲突这种问题排查起来非常消耗精力。应用拆分的原则是职责单一。比如一个内容管理后台你可以拆成accounts、articles、comments三个应用而不是把用户、文章、评论全部塞进一个 app 里。每个 app 负责自己的数据模型、视图、路由和模板后续扩展、测试、维护都会轻松很多。初始化阶段不要怕多建 app怕的是把所有代码堆在一个文件里等业务复杂了再拆拆一半就是灾难现场。目录结构还有一个值得关注的细节是否用apps目录把多个业务应用统一收纳。项目规模小的时候平铺在根目录下完全没问题但一旦应用数量超过五六个根目录会变得很杂乱。我见过一个项目把十几个 app 全放在根目录下每次打开工程都得滚动半天。比较合理的做法是先平铺等 app 多了再统一迁移到apps包下或者从一开始就规划好。初始化阶段可以不必过度设计但你心里要对未来的演进方向有数。1.3 哪些配置必须在动手前想清楚有几类配置如果在初始化阶段没有想清楚后面改起来会非常痛。第一个就是自定义用户模型这个必须在一开始迁移数据库之前决定好因为 Django 的auth和admin应用会在第一次迁移时创建关联表一旦表结构已经落地再想换掉默认的User模型基本等于把数据库删了从零开始。所以新项目只要有一丁点可能扩展用户字段我都建议第一步就用AbstractUser自定义一个用户模型并配置好AUTH_USER_MODEL。第二个需要前置决策的是数据库方言。默认 SQLite 确实零配置、上手快但如果你知道项目将来要上 MySQL 或 PostgreSQL最好在初始化阶段就把数据库配置准备好。不同数据库对字段类型、索引、事务行为的支持有差异尤其是迁移文件在两个引擎之间切换时很容易出现字段长度、JSON 字段支持度不一致的问题。我个人的习惯是如果确定最终要上 MySQL开发环境也直接连 MySQL避免后期迁移踩到方言差异的坑。第三个是配置管理方案。settings 文件里放着SECRET_KEY、数据库密码、第三方 API Key 等敏感信息这些绝对不能硬编码在代码仓库里。我会在初始化阶段就引入环境变量机制用一个.env文件配合python-dotenv读取同时把.env加进.gitignore。这样代码入库时只有模板没有密钥换环境部署也只需要改环境变量清爽很多。2. settings.py 里的关键配置每个选项背后的理由2.1 SECRET_KEY 与 DEBUG安全底线从第一天就要立住SECRET_KEY在 Django 里承担着会话加密、密码重置令牌、签名数据校验等核心职责。它的作用相当于一栋大楼的总钥匙一旦泄露攻击者就能伪造 session、篡改签名数据等于拿到了整个系统的访问权限。新项目自动生成的SECRET_KEY是可以用的但它会直接出现在代码里提交到仓库就是安全隐患。我通常这样处理把密钥移到环境变量中代码里用os.environ.get(DJANGO_SECRET_KEY)读取本地开发在.env中提供默认值生产环境由部署平台注入。DEBUG选项看起来简单实则影响巨大。DEBUGTrue时Django 会输出完整错误页面包括堆栈信息、本地变量、settings 配置值数据库密码和密钥都可能直接暴露在浏览器上。生产环境一旦开着DEBUG就相当于给攻击者搭了一个免费的侦察接口。所以初始化阶段就要定下规则开发环境用DEBUGTrue测试和生产环境强制DEBUGFalse。我习惯在 settings 里直接写DEBUG os.environ.get(DJANGO_DEBUG, True) True这类条件配合环境变量切换环境。ALLOWED_HOSTS是容易被忽略的一项。当DEBUGFalse时Django 只允许请求的Host头出现在ALLOWED_HOSTS列表里否则会直接抛出Bad Request。这么做是为了防止 DNS rebinding 攻击。开发阶段用[localhost, 127.0.0.1]就够了内网联调时再按需添加 IP 或域名。我见过有同学图省事直接写成[*]这在生产环境是隐患一旦部署服务商把域名解析到你的实例上你的代码也照单收下很容易被恶意请求打到。2.2 数据库配置SQLite 起步还是直上 MySQL默认的 SQLite 适合快速原型它不需要启动服务不用配账号密码数据就是一个文件随拿随走。但如果项目要长期维护我建议尽早切换到真正的数据库服务。SQLite 虽然轻量但并发写能力弱多进程同时写库时容易锁表数据量大之后拆库扩容也麻烦。初始化阶段切换数据库成本很低等业务代码写多了再切换迁移工作量会成倍上升。以 MySQL 为例DATABASES配置至少要包括ENGINE、NAME、USER、PASSWORD、HOST、PORT这六项。需要用mysqlclient作为驱动它会依赖系统里的 MySQL 客户端库。如果你在 Windows 上装这个库遇到编译失败我后面会在排查部分专门说一种替代方案。使用 PostgreSQL 同理驱动换psycopg2ENGINE换成django.db.backends.postgresql。关键是连接池和超时参数可以在OPTIONS里配置但不是必须的初始化阶段先把连通性跑通就好。关于字符集MySQL 建议统一使用utf8mb4它比utf8多支持 emoji 和生僻字排序规则也更好。这个问题我在老项目里遇到过评论里有人发了生僻字数据库直接报Incorrect string value最后只能改表结构。初始化阶段把字符集定好后面就不会有这种破事。CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;这一步最好在初始化时完成而不是等项目上线之后再补课。2.3 时区、语言与静态文件容易被忽略的基础设施时区配置看起来不起眼但踩坑的人非常多。USE_TZTrue时Django 在数据库里统一存储 UTC 时间展示时再根据TIME_ZONE转换。如果你只在国内使用TIME_ZONE建议设为Asia/ShanghaiLANGUAGE_CODE设为zh-hans。否则你会遇到一个经典问题模型里auto_now_addTrue的时间字段取出来总觉得少了 8 个小时那是因为数据库中存的是 UTC 时间模板展示时没有按当前时区转换。养成在模板里用localtime过滤器或者代码里用timezone.localtime()处理时间的习惯就能避开这个坑。静态文件和媒体文件的配置是初始化阶段很值得做对的一环。开发环境里 Django 的runserver能自动服务静态文件但生产环境必须用collectstatic收集到统一目录再交给 Nginx 或 CDN 处理。因此 settings 里至少要有STATIC_URL、STATIC_ROOT、STATICFILES_DIRS媒体文件则对应MEDIA_URL和MEDIA_ROOT。我通常会在项目根目录建static/和media/两个目录其中media在.gitignore里忽略因为上传文件不应该进仓库。初始化阶段就把这些基础设施铺好看起来多花了一点时间但省掉的是日后部署时的返工。尤其是STATIC_ROOT的配置我见过一个项目直到上线前一天才发现collectstatic没有收集到 admin 的静态文件页面样式全丢了临时补配置手忙脚乱。提前配置好后面真正部署的时候只需要跑一条命令就够了。2.4 自定义用户模型错过时机再改就晚了Django 默认的用户模型只有用户名、密码、邮箱等基础字段但实际项目中几乎总会需要手机号、昵称、头像、性别等扩展字段。默认模型的最大问题是它的表结构在第一次migrate时就被auth应用创建了之后你再想换自定义模型Django 会提示你已经有关联表除了删库重建没有干净的办法。自定义用户模型的标准做法是继承AbstractUser然后加上你要的字段。比如from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): phone models.CharField(max_length11, blankTrue) nickname models.CharField(max_length64, blankTrue)然后在 settings 中注册AUTH_USER_MODEL accounts.User这里有个细节容易被忽略必须在第一次执行makemigrations和migrate之前配置完成。原因在于 Django 的auth、admin、sessions等内置应用会在首次迁移时通过外键关联用户模型一旦这些表生成再更换用户模型Django 会报AttributeError或者产生大量表重建需求。我接手过一些项目初始化时偷懒用了默认模型后期要加手机号登录只能放弃原有用户数据表从头迁移这个教训非常深刻。另外自定义用户模型还会影响admin后台的显示和注册方式。你需要用UserAdmin或其子类来注册自定义模型否则后台可能无法正常渲染。初始化阶段用AbstractUser不会改变登录方式但你已经有了扩展能力后续加字段、改认证方式都不用伤筋动骨。3. 实操过程从零到能跑通的完整初始化流程3.1 创建虚拟环境与安装 Django我假设你已经装好了 Python并且能在命令行里调用python。第一步是创建项目目录并进入mkdir myproject cd myproject接着创建虚拟环境。在 Windows 上如果python命令不可用可以试试py命令python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 source venv/bin/activate激活成功后命令行会多出(venv)前缀实测下来这就是虚拟环境在生效的信号。接下来可以顺手升级一下 pip避免后续安装依赖时出现版本解析问题python -m pip install --upgrade pip安装 Django 可以选择指定版本我推荐拿到确切的 LTS 版本来锁定环境。比如pip install Django5.2.4装完后用一行命令验证版本确认当前环境中 Django 可被正常导入python -c import django; print(django.get_version())这里有个容易栽的坑如果你发现输出的版本和刚安装的不一致很可能是全局环境里的 Django 在起作用说明虚拟环境没有成功激活。可以先执行which python确保当前解释器在虚拟环境目录下再继续。装包速度慢的话可以换国内 PyPI 镜像源比如在 pip 命令后面加上镜像地址。3.2 startproject 与 startapp项目骨架的正确姿势创建项目骨架时我习惯把配置目录命名为config而不是写项目名然后用点号表示在当前目录生成django-admin startproject config .这条命令会在当前目录生成一个manage.py和一个config包。manage.py是后续所有管理命令的入口它把 settings 模块、应用的启动方式都串联起来了。为什么这里强调用.因为不写的话Django 会再额外建一层同名目录目录结构变得冗余。用.生成的布局更干净也方便你直接在根目录下建各种业务应用。接着创建第一个业务应用比如用户模块python manage.py startapp accounts此时你的项目结构应当是manage.py、config/、accounts/。打开accounts/models.py先定义好自定义用户模型。按 2.4 节的方式继承AbstractUser然后在config/settings.py里加上AUTH_USER_MODEL accounts.User。同时把accounts加入INSTALLED_APPS。这个列表中的顺序会影响模板查找、迁移生成顺序和 admin 注册通常把自己的应用放在内置应用之后。还要顺手在config/urls.py里配置根路由把应用的 URL 接入进来。这一步不做后续访问accounts相关页面时会直接 404。配置好之后再执行迁移顺序非常重要先保证AUTH_USER_MODEL已配置再生成迁移文件最后再迁移数据库。3.3 数据库迁移与超级用户创建配置好模型之后真正让表结构落地的是三步命令。先执行python manage.py makemigrations这个命令会扫描所有已注册应用根据模型变化生成迁移文件。如果你修改了用户模型这里会看到accounts下生成了对应的迁移文件。如果有一个No changes detected的提示说明你的模型没有变化或者应用没有被正确加入INSTALLED_APPS。接着真正执行迁移python manage.py migrate这条命令会把所有应用的迁移文件按依赖顺序应用到数据库里。执行完毕后数据库里会出现auth_user或你自定义的用户表以及admin、sessions等内置应用的相关表。如果项目用的是 SQLite可以直接用数据库工具打开db.sqlite3查看表结构确认用户表字段确实包含你的扩展字段。然后是创建后台管理员账号python manage.py createsuperuser根据提示输入用户名、邮箱和密码。这里有个小技巧密码输入时不显示字符是正常现象不是键盘坏了。创建完成后可以启动开发服务器验证整条链路python manage.py runserver浏览器打开http://127.0.0.1:8000/你应该能看到 Django 的默认欢迎页。再访问http://127.0.0.1:8000/admin/用刚创建的超级用户登录如果能进入后台管理界面说明项目主体已经初始化成功。整个过程跑通标志着从建项目到能跑这一步已经走完。3.4 补充工程化配置环境变量、依赖导出与 .gitignore项目能跑只是开始我还会在初始化阶段把下面这几样补上它们决定了这个项目能不能在团队里协作、能不能顺利部署。先做环境变量文件。在项目根目录创建.env写入需要敏感配置的内容DJANGO_SECRET_KEYyour-secret-key DJANGO_DEBUGTrue DJANGO_ALLOWED_HOSTSlocalhost,127.0.0.1在 settings.py 里通过python-dotenv读取。安装依赖pip install python-dotenv然后在settings.py顶部加上import os from dotenv import load_dotenv load_dotenv() SECRET_KEY os.environ.get(DJANGO_SECRET_KEY, fallback-dev-key) DEBUG os.environ.get(DJANGO_DEBUG, True) True ALLOWED_HOSTS os.environ.get(DJANGO_ALLOWED_HOSTS, localhost,127.0.0.1).split(,)可以给SECRET_KEY设置一个只在本地开发时使用的后备值但生产环境必须从环境变量注入真实密钥。同时记得把.env写进.gitignore否则密钥还是会跟仓库走。接着导出依赖清单pip freeze requirements.txt这份文件锁定了当前环境中的所有依赖版本团队其他人拉下代码后执行pip install -r requirements.txt就能复现环境。最后创建.gitignore至少要包含以下条目venv/ __pycache__/ *.pyc .env db.sqlite3 media/ staticfiles/到这里一个工程化的 Django 项目初始化才算完整。模板已经有了、数据库已经通了、管理员已经建好了、敏感信息已经隔离了、依赖已经锁定了后续开发就像在铺好的地基上盖房子不用再回头补基础设施。4. 常见问题与排查技巧初始化阶段的避坑实录4.1 环境与依赖引发的报错我在初始化阶段见过最多的问题几乎都集中在环境上。最常见的是明明安装了 Django却提示ModuleNotFoundError。这种情况大概率是全局环境与虚拟环境混用了。用which python和pip list检查一下当前解释器路径和安装位置如果指向的不是虚拟环境里的路径重新激活环境或者干脆重建虚拟环境。还有个细节Windows 上如果使用 PowerShell激活脚本路径是venv\Scripts\Activate.ps1如果执行策略限制脚本运行可以临时用Set-ExecutionPolicy -ExecutionPolicy RemoteSigned放开或者直接用venv\Scripts\activate.bat。第二个常见问题是安装mysqlclient时编译失败。这个库在 Windows 上需要 C 编译器而且和系统的 MySQL 客户端库版本相关报错信息经常是error: command gcc failed看起来非常吓人。我实测下来最省事的替代方案是使用PyMySQLpip install pymysql然后在项目的__init__.py里做兼容import pymysql pymysql.install_as_MySQLdb()这样 Django 仍然以django.db.backends.mysql连接但底层驱动变成了纯 Python 实现免去编译环境折腾。注意这个install_as_MySQLdb()必须在任何数据库操作前执行通常放在config/__init__.py中比较合适。第三个问题是端口被占用。runserver默认占用 8000如果你之前启动过其他服务还驻留在那里执行命令会直接报Address already in use。不必纠结谁占用了端口直接换端口跑python manage.py runserver 8001这种处理方式在本地开发时最灵活还解决了多个项目同时开发的端口冲突问题。想更好用的可以直接设一个别名命令但初始化阶段手动指定端口就够了。4.2 数据库与迁移相关的疑难杂症迁移阶段的问题比环境问题更隐蔽。一种经典情况是执行migrate后代码运行时提示表不存在。比如OperationalError: no such table: accounts_user说明迁移没有真正应用到当前连接的数据库。先检查DATABASES配置是不是指向了你以为的那个库再确认是否执行了migrate最后用数据库工具直接看表是否存在。还有一种可能是你换了数据库文件或修改了连接串但迁移状态记录并没有同步。另一种常见问题是迁移文件冲突。当两个人各自在分支里基于同一个初始状态添加了模型字段合并代码后执行迁移Django 会检测到多个迁移文件有共同的依赖点然后要求手动合并。此时可以执行python manage.py makemigrations --merge它会生成一个空的合并迁移把冲突的迁移文件统一接到一个依赖节点上。注意先去检查两支迁移改动的内容确认没有互相覆盖再执行合并否则数据字段会有隐藏丢失。处理完--merge后再migrate基本就能恢复正常的迁移链路。还有一个我经常提醒别人的坑你是用什么版本的 Python 生成的迁移不同 Python 版本的字典排序不一致可能导致迁移文件里的字段顺序不同。团队协作时尽量统一 Python 版本和依赖版本否则会出现我这边没问题你那边就跑不起来的鬼畜情况。初始化阶段把开发环境约定写进 README或者直接用.python-version这类工具锁定版本能省去很多沟通成本。4.3 初始化完成后的自检清单跑通了不代表真的初始化干净了我每次做完初始化都会对照下面这份清单做一次快速自检检查项检查方式虚拟环境已激活which python指向venv目录依赖已锁定本地存在requirements.txt迁移已执行python manage.py migrate无报错超级用户可用能登录admin后台敏感配置已隔离.env在.gitignore中静态文件可收集python manage.py collectstatic --noinput无报错数据库可读写在shell里做一次简单的 ORM 插入查询应用已注册INSTALLED_APPS包含所有业务应用我会在最后一步做一次真实读写验证通常是在 shell 里创建一个用户对象并保存再查出来打印一遍。这能确认数据库连接、字符编码、时区设置都正常工作。不要只依赖runserver看到欢迎页就收工欢迎页只是 Django 跑在内存里的证明不代表数据库链路是通的。关于时区还有一个容易被忽略的细节是数据库连接的时区参数。MySQL 连接时可以通过OPTIONS指定字符集和时区OPTIONS: { charset: utf8mb4, init_command: SET time_zone 08:00, }这样能避免应用层和数据库层的时区语义不一致导致时间字段出现偏差。如果你在后端读取时间时经常和前端时间对不上先回来检查这一层别急着去调前端。初始化的流程不算复杂但每个决定都在为项目的未来投票。我个人的体会是宁可多花半小时把自定义用户模型、数据库方言、SECRET_KEY 这些前置决策做好也不要等项目代码写了一堆之后再回头重构。最后再分享一个小技巧初始化完成后把整个流程写进项目的 README 或者部署文档里下次开新项目照着走一遍省时省力还能让团队所有人在同一个起跑线上开始开发。
阅读完成 · 觉得有帮助?