Django从零开始(十):项目部署与性能优化
一、部署概述
将Django项目从开发环境迁移到生产环境,需要考虑性能、稳定性、安全性三个方面。本章将介绍从服务器搭建到线上运维的完整流程。
生产环境架构
# 常见的Django生产部署架构
# 方案1:Nginx + Gunicorn + Django(最经典)
用户 → Nginx(80/443) → Gunicorn(8000) → Django
# 方案2:Nginx + uWSGI + Django
用户 → Nginx(80/443) → uWSGI(8000) → Django
# 方案3:Docker + Nginx + Gunicorn
用户 → Nginx容器 → Gunicorn容器 → Django
# 完整架构(含缓存和数据库)
用户 → Nginx → Gunicorn → Django → PostgreSQL
↕ ↕
Redis Celery → RabbitMQ
二、Gunicorn部署
2.1 安装与配置
# 安装Gunicorn
pip install gunicorn
# 基本启动
gunicorn mysite.wsgi:application
# 生产环境推荐参数
gunicorn mysite.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 4 \
--threads 2 \
--timeout 120 \
--access-logfile - \
--error-logfile - \
--log-level info \
--name mysite
2.2 Gunicorn配置文件
# gunicorn.conf.py
import multiprocessing
import os
# 服务器绑定
bind = '127.0.0.1:8000'
# Worker数量(推荐 2 * CPU核心数 + 1)
workers = multiprocessing.cpu_count() * 2 + 1
# 每个Worker的线程数
threads = 2
# Worker超时时间(秒)
timeout = 120
# 最大并发请求数(之后重启worker,防止内存泄漏)
max_requests = 5000
max_requests_jitter = 500
# 日志
accesslog = '/var/log/gunicorn/access.log'
errorlog = '/var/log/gunicorn/error.log'
loglevel = 'info'
# 进程命名
proc_name = 'mysite'
# Worker临时目录
worker_tmp_dir = '/dev/shm' # 使用内存文件系统提升性能
# 预加载应用(减少内存占用,但更新需重启)
preload_app = True
# 优雅重启
graceful_timeout = 30
keepalive = 5
2.3 Systemd服务配置
# /etc/systemd/system/mysite.service
[Unit]
Description=MySite Django Application
After=network.target postgresql.service redis.service
[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/var/www/mysite
ExecStart=/var/www/mysite/venv/bin/gunicorn \
--config /var/www/mysite/gunicorn.conf.py \
mysite.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=30
PrivateTmp=true
Environment="DJANGO_SETTINGS_MODULE=mysite.settings"
[Install]
WantedBy=multi-user.target
# 管理命令
sudo systemctl start mysite
sudo systemctl enable mysite # 开机自启
sudo systemctl status mysite
sudo systemctl reload mysite # 优雅重载
sudo systemctl restart mysite
三、Nginx配置
# /etc/nginx/sites-available/mysite
# HTTP → HTTPS重定向
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}
# HTTPS配置
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL证书
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# SSL优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 日志
access_log /var/log/nginx/mysite_access.log;
error_log /var/log/nginx/mysite_error.log;
# 静态文件(Nginx直接处理,性能远超Django)
location /static/ {
alias /var/www/mysite/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
}
# 媒体文件
location /media/ {
alias /var/www/mysite/media/;
expires 7d;
}
# favicon
location = /favicon.ico {
alias /var/www/mysite/staticfiles/favicon.ico;
access_log off;
log_not_found off;
}
# 代理到Gunicorn
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 30s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# 文件上传大小限制
client_max_body_size 10M;
}
四、Docker部署
4.1 Dockerfile
# Dockerfile
# 多阶段构建
FROM python:3.12-slim AS builder
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 生产阶段
FROM python:3.12-slim
WORKDIR /app
# 安装运行时依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
curl \
&& rm -rf /var/lib/apt/lists/*
# 从builder复制Python包
COPY --from=builder /usr/local/lib/python3.12/site-packages/ /usr/local/lib/python3.12/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
# 复制项目代码
COPY . .
# 收集静态文件
RUN python manage.py collectstatic --noinput
# 创建非root用户
RUN useradd -m -r appuser && chown -R appuser:appuser /app
USER appuser
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:8000/health/ || exit 1
EXPOSE 8000
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"]
4.2 Docker Compose
# docker-compose.yml
version: '3.8'
services:
# Django应用
web:
build: .
container_name: mysite-web
restart: always
env_file: .env
volumes:
- ./media:/app/media
- staticfiles:/app/staticfiles
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- mysite-network
# Nginx
nginx:
image: nginx:1.25-alpine
container_name: mysite-nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
- staticfiles:/var/www/staticfiles:ro
- ./media:/var/www/media:ro
depends_on:
- web
networks:
- mysite-network
# PostgreSQL
db:
image: postgres:16-alpine
container_name: mysite-db
restart: always
environment:
POSTGRES_DB: mysite
POSTGRES_USER: mysite
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mysite"]
interval: 10s
timeout: 5s
retries: 5
networks:
- mysite-network
# Redis
redis:
image: redis:7-alpine
container_name: mysite-redis
restart: always
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- mysite-network
# Celery Worker
celery:
build: .
container_name: mysite-celery
restart: always
command: celery -A mysite worker -l info --concurrency=4
env_file: .env
depends_on:
- redis
- db
networks:
- mysite-network
# Celery Beat(定时任务)
celery-beat:
build: .
container_name: mysite-celery-beat
restart: always
command: celery -A mysite beat -l info
env_file: .env
depends_on:
- redis
networks:
- mysite-network
volumes:
postgres_data:
redis_data:
staticfiles:
networks:
mysite-network:
driver: bridge
五、Celery异步任务
# 安装
pip install celery redis
# mysite/celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
app = Celery('mysite')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# settings.py
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
# blog/tasks.py
from celery import shared_task
from django.core.mail import send_mail
@shared_task
def send_welcome_email(user_id):
"""发送欢迎邮件"""
from django.contrib.auth.models import User
user = User.objects.get(id=user_id)
send_mail(
'欢迎注册',
f'你好 {user.username},欢迎加入我们!',
'noreply@example.com',
[user.email],
)
@shared_task
def generate_report():
"""生成每日报告"""
# 生成统计报告
pass
# 在视图中调用
from .tasks import send_welcome_email
def register(request):
# ...
send_welcome_email.delay(user.id) # 异步执行
六、性能优化
6.1 数据库优化
# 1. 使用select_related减少查询(ForeignKey/OneToOne)
# 不好:N+1查询问题
articles = Article.objects.all()
for article in articles:
print(article.category.name) # 每次循环都查询一次数据库
# 好:使用select_related(JOIN查询)
articles = Article.objects.select_related('category', 'author').all()
for article in articles:
print(article.category.name) # 不再额外查询
# 2. 使用prefetch_related减少查询(ManyToMany/反向ForeignKey)
articles = Article.objects.prefetch_related('tags').all()
# 3. 组合使用
articles = Article.objects.select_related(
'category', 'author'
).prefetch_related(
'tags', 'comments'
).filter(status='published')
# 4. 只查询需要的字段
articles = Article.objects.only('title', 'slug', 'created_at')
# 5. 使用defer排除大字段
articles = Article.objects.defer('content') # 不查询content字段
# 6. 批量操作
Article.objects.bulk_create([
Article(title='文章1', slug='article-1', author=user),
Article(title='文章2', slug='article-2', author=user),
Article(title='文章3', slug='article-3', author=user),
])
Article.objects.bulk_update(articles, ['title', 'status'])
# 7. 添加数据库索引
class Meta:
indexes = [
models.Index(fields=['-created_at']),
models.Index(fields=['status', 'is_top']),
]
6.2 查询性能分析
# 查看查询SQL
print(Article.objects.filter(status='published').query)
# 查看查询次数(检测N+1问题)
from django.db import connection
queries = connection.queries
print(f"Total queries: {len(queries)}")
for q in queries:
print(q['sql'], q['time'])
# 使用assertNumQueries测试查询次数
from django.test.utils import override_settings
def test_query_count(self):
with self.assertNumQueries(2): # 期望只有2次查询
response = self.client.get('/api/articles/')
6.3 静态文件优化
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# 收集静态文件
python manage.py collectstatic
# 使用WhiteNoise直接从Django提供静态文件(适合小项目)
pip install whitenoise
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # 紧跟Security之后
...
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
七、环境变量管理
# 安装python-dotenv
pip install python-dotenv
# .env文件(不提交到Git)
DEBUG=False
SECRET_KEY=your-secret-key-here
DATABASE_URL=postgres://user:pass@localhost:5432/mysite
REDIS_URL=redis://localhost:6379/0
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
# settings.py
from dotenv import load_dotenv
import os
load_dotenv()
SECRET_KEY = os.environ.get('SECRET_KEY')
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
# 使用dj-database-url解析数据库URL
pip install dj-database-url
import dj_database_url
DATABASES = {
'default': dj_database_url.parse(
os.environ.get('DATABASE_URL'),
engine='django.db.backends.postgresql',
)
}
八、CI/CD自动化部署
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -r requirements.txt
- run: python manage.py test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/mysite
git pull origin main
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart mysite
九、监控与运维
# 健康检查端点
from django.http import JsonResponse
from django.db import connection
def health_check(request):
"""健康检查API"""
checks = {'database': False, 'cache': False}
try:
connection.ensure_connection()
checks['database'] = True
except Exception:
pass
from django.core.cache import cache
try:
cache.set('health', 'ok', 1)
checks['cache'] = cache.get('health') == 'ok'
except Exception:
pass
is_healthy = all(checks.values())
return JsonResponse(checks, status=200 if is_healthy else 503)
十、系列总结
恭喜你完成了Django从零开始的全部学习!让我们回顾一下10章的核心内容:
| 章节 | 主题 | 核心内容 |
|---|---|---|
| 1 | 环境搭建 | 虚拟环境、项目创建、settings配置 |
| 2 | 模型与ORM | 字段类型、关系字段、CRUD、高级查询 |
| 3 | 视图与路由 | FBV/CBV、URL配置、请求响应对象 |
| 4 | 模板系统 | 模板语法、继承、自定义标签过滤器 |
| 5 | 表单处理 | Form/ModelForm、验证器、文件上传 |
| 6 | 用户认证 | 注册登录、权限系统、社交登录 |
| 7 | REST API | DRF序列化器、视图集、JWT认证 |
| 8 | 中间件/信号/缓存 | 请求管道、事件处理、Redis缓存 |
| 9 | 测试与安全 | 单元测试、API测试、安全防护 |
| 10 | 部署优化 | Gunicorn/Nginx、Docker、性能优化 |
掌握这些知识后,你已经具备了独立开发完整Django项目的能力。接下来建议:
- 动手做一个完整的项目(博客系统、电商网站等)
- 阅读Django官方文档深入理解
- 学习前端框架(Vue.js/React)配合Django后端
- 关注Django新版本的更新内容
祝你Django开发之旅一切顺利!🚀
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。







