3. 项目骨架搭建:Django项目创建、目录结构规范、配置文件分层设计
好,咱们进入第三章。说实话,很多新手拿到一个项目,上来就 django-admin startproject 一把梭。结果呢?项目跑起来了,但三个月后,连自己都看不懂自己写的配置。我见过太多这样的烂摊子了。
这一章,我就带你搭一个「能打硬仗」的项目骨架。不是花架子,是真正能在生产环境里扛住压力的结构。
3.1 创建Django项目,别急着敲命令
先想清楚一件事:你的项目是给谁用的?是给内部运营的小工具,还是面向百万用户的电商平台?
我个人习惯,在创建项目之前,先画一个简单的目录树。哪怕只是在纸上画两笔。这能帮你理清思路。
好,假设我们要做一个电商后台。先创建项目:
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Windows用 venv\Scripts\activate
# 安装Django
pip install django
# 创建项目
django-admin startproject ecommerce_backend
cd ecommerce_backend
嗯,这里要注意。默认生成的目录结构太「平」了。所有东西都堆在根目录下,看着就头疼。我们需要动动手,把它改造成更适合团队协作的样子。
3.2 目录结构规范:让每个人都能找到东西
我在项目中遇到过最痛苦的事,就是找一个配置文件要翻五个文件夹。后来我总结了一套结构,用了好几年,团队里新人也很快能上手。
改造后的目录结构长这样:
ecommerce_backend/
├── apps/ # 所有业务应用放这里
│ ├── users/ # 用户模块
│ ├── products/ # 商品模块
│ ├── orders/ # 订单模块
│ └── payments/ # 支付模块
├── config/ # 配置文件集中管理
│ ├── settings/ # 分层配置
│ │ ├── base.py # 公共配置
│ │ ├── dev.py # 开发环境
│ │ ├── prod.py # 生产环境
│ │ └── test.py # 测试环境
│ ├── urls.py # 根路由
│ └── wsgi.py # WSGI入口
├── libs/ # 公共库、工具函数
│ ├── utils/ # 通用工具
│ └── middleware/ # 自定义中间件
├── static/ # 静态文件
├── media/ # 用户上传文件
├── templates/ # 模板文件
├── scripts/ # 运维脚本、管理命令
├── docs/ # 项目文档
├── requirements/ # 依赖管理
│ ├── base.txt
│ ├── dev.txt
│ └── prod.txt
├── manage.py
└── .env # 环境变量(不提交到git)
核心原则:按功能分层,而不是按文件类型分层。把「配置」放一起,把「业务」放一起,把「工具」放一起。这样你找东西的时候,脑子不用切换上下文。
你想想看,如果所有配置都散落在各个app里,改个数据库连接要翻遍整个项目。集中管理之后,改配置只需要去 config/settings/ 这一个地方。
3.3 配置文件分层设计:为什么需要三层?
说白了,开发环境和生产环境的需求完全不同。开发时你需要调试工具、宽松的跨域设置;生产环境则需要关闭调试、开启缓存、严格的安全策略。
我曾经见过一个项目,开发和生产用同一个配置文件。每次上线前,手动改 DEBUG = True 为 False。结果有一次忘了改,线上直接暴露了源码路径……嗯,从那以后,我再也不敢用单文件配置了。
分层设计的好处:
| 配置层 | 用途 | 典型内容 |
|---|---|---|
base.py |
所有环境共享 | INSTALLED_APPS、数据库引擎、时区、语言 |
dev.py |
本地开发 | DEBUG=True、SQLite、django-debug-toolbar |
prod.py |
生产环境 | DEBUG=False、PostgreSQL、Redis缓存、HTTPS |
test.py |
自动化测试 | 内存数据库、快速密码哈希器 |
具体怎么实现?看代码:
# config/settings/base.py
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'fallback-dev-key')
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ... 其他公共app
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# ... 公共中间件
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
# ...
},
]
# 数据库配置只留引擎,具体参数由子类覆盖
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# 时区、语言等公共设置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = True
# config/settings/dev.py
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['*']
INSTALLED_APPS += [
'debug_toolbar',
]
MIDDLEWARE += [
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
# 开发环境用本地文件存储
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# 打印SQL日志
LOGGING = {
'version': 1,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
},
},
}
# config/settings/prod.py
from .base import *
import os
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
# 生产环境用PostgreSQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ.get('DB_PORT', '5432'),
}
}
# 静态文件由Nginx处理
STATIC_ROOT = '/var/www/static'
STATIC_URL = '/static/'
MEDIA_ROOT = '/var/www/media'
MEDIA_URL = '/media/'
# 安全配置
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# 缓存用Redis
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': os.environ['REDIS_URL'],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
小技巧:在 manage.py 中通过环境变量 DJANGO_SETTINGS_MODULE 来指定使用哪个配置。比如本地开发时:export DJANGO_SETTINGS_MODULE=config.settings.dev。这样你就不用改任何代码,切换环境只需要改一个环境变量。
3.4 如何选择配置?用环境变量驱动
你可能会问:每次手动改环境变量不也麻烦吗?
没错,所以我们需要一个 .env 文件。配合 python-decouple 或 django-environ 这类库,自动加载环境变量。
# .env 文件(不提交到git)
DJANGO_SETTINGS_MODULE=config.settings.dev
DJANGO_SECRET_KEY=your-secret-key-here
DB_NAME=ecommerce_db
DB_USER=postgres
DB_PASSWORD=strong_password_123
# manage.py 顶部加入
import os
import dotenv
dotenv.load_dotenv()
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.dev')
这样一来,每个开发者只需要维护自己的 .env 文件。生产环境由运维同学在部署时注入真实的环境变量。代码里不出现任何敏感信息。
警告:千万不要把 .env 文件提交到Git仓库!在 .gitignore 中加上 .env。我见过有人把数据库密码直接写死在代码里,然后上传到GitHub……那场面,简直是灾难。
3.5 启动验证:检查你的骨架是否稳固
结构搭好了,我们来验证一下:
# 设置环境变量
export DJANGO_SETTINGS_MODULE=config.settings.dev
# 运行迁移
python manage.py migrate
# 启动开发服务器
python manage.py runserver
# 如果能正常启动,说明骨架没问题
# 访问 http://127.0.0.1:8000 看到Django欢迎页
如果报错,多半是路径问题。检查 BASE_DIR 的计算是否正确。我刚开始用这种分层结构时,也经常搞错路径层级。后来我习惯在 base.py 里加一行 print(BASE_DIR),确认路径对了再继续。
3.6 小结:骨架决定了项目能长多大
这一章我们做了三件事:
- 创建了项目,但没直接用默认结构
- 重构了目录,让业务、配置、工具各归其位
- 分层了配置,用环境变量驱动不同环境
这套骨架我用了好几年,从几十万用户的小项目到千万级流量的平台,都扛得住。说白了,好的骨架不是一蹴而就的,而是在一次次重构中打磨出来的。但至少,我们从第一天开始就别给自己挖坑。
下一章,我们会在这个骨架上填充血肉——开始搭建用户模块。到时候你会看到,今天搭的骨架有多重要。