浏览知识库目录

Python

配置、中间件、信号与管理命令

配置、中间件、信号与管理命令

本篇介绍 Django 的常用扩展点:多环境配置、中间件、信号、自定义管理命令和应用启动配置。它们能让项目结构更清楚,但也容易被滥用。


一、按环境拆分配置

推荐结构:

mysite/
  settings/
    __init__.py
    base.py
    development.py
    production.py

base.py 保存公共配置,development.pyproduction.py 只覆盖差异。

# settings/development.py
from .base import *

DEBUG = True
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]

启动时指定配置:

$env:DJANGO_SETTINGS_MODULE = "mysite.settings.development"
python manage.py runserver

manage.pywsgi.pyasgi.py 也可设置默认配置模块。


二、读取环境变量

import os

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
DEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"
ALLOWED_HOSTS = [
    host.strip()
    for host in os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")
    if host.strip()
]

生产密钥、数据库密码、邮件密码和第三方令牌不能写入仓库。可以提交 .env.example 说明需要哪些变量,但不放真实值。

关键配置缺失时应快速失败,使用 os.environ["NAME"] 比悄悄使用不安全默认值更可靠。


三、中间件是什么

中间件包裹整个请求/响应流程,适合处理跨应用的通用逻辑,例如安全头、会话、认证、请求 ID 和耗时记录。

# core/middleware.py
import time
import uuid


class RequestContextMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
        started = time.monotonic()

        response = self.get_response(request)

        response["X-Request-ID"] = request.request_id
        response["Server-Timing"] = f"app;dur={(time.monotonic() - started) * 1000:.2f}"
        return response

MIDDLEWARE 中注册:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "core.middleware.RequestContextMiddleware",
]

请求阶段按从上到下执行,响应阶段按从下到上返回。依赖 request.user 的中间件必须放在认证中间件之后。


四、信号

信号允许某个事件发生后通知其他代码:

# notes/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver

from .models import Message, MessageAudit


@receiver(post_save, sender=Message)
def create_message_audit(sender, instance, created, **kwargs):
    if created:
        MessageAudit.objects.create(message=instance, action="created")

在应用配置中导入信号:

# notes/apps.py
from django.apps import AppConfig


class NotesConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "notes"

    def ready(self):
        from . import signals  # noqa: F401

信号适合弱耦合的附加行为,不适合隐藏核心业务流程。付款、扣库存等关键操作应由明确的服务函数调用,这样顺序和事务边界更清楚。

注意:bulk_create()bulk_update() 和 QuerySet update() 不会触发常规模型保存信号。


五、自定义管理命令

目录:

notes/
  management/
    __init__.py
    commands/
      __init__.py
      archive_messages.py
from datetime import timedelta

from django.core.management.base import BaseCommand
from django.utils import timezone

from notes.models import Message


class Command(BaseCommand):
    help = "归档指定天数以前的留言"

    def add_arguments(self, parser):
        parser.add_argument("--days", type=int, default=90)
        parser.add_argument("--dry-run", action="store_true")

    def handle(self, *args, **options):
        cutoff = timezone.now() - timedelta(days=options["days"])
        queryset = Message.objects.filter(created_at__lt=cutoff)

        if options["dry_run"]:
            self.stdout.write(f"将归档 {queryset.count()} 条留言")
            return

        updated = queryset.update(status="archived")
        self.stdout.write(self.style.SUCCESS(f"已归档 {updated} 条留言"))

运行:

python manage.py archive_messages --days 180 --dry-run

批处理命令应支持幂等、日志、失败重试和 --dry-run,并避免一次把海量对象全部加载进内存。


六、系统检查框架

可以为项目关键配置增加检查:

from django.conf import settings
from django.core.checks import Error, register


@register()
def check_support_email(app_configs, **kwargs):
    if not getattr(settings, "SUPPORT_EMAIL", ""):
        return [Error("缺少 SUPPORT_EMAIL 配置", id="core.E001")]
    return []

执行 python manage.py check 时会一起检查。


七、常见问题

  • 生产读取到开发配置:DJANGO_SETTINGS_MODULE 指向错误。
  • 中间件访问不到 request.user:顺序早于认证中间件。
  • 信号重复执行:模块被重复注册,或测试/开发加载逻辑不清晰。
  • 批量更新后信号没触发:这是 ORM 批量操作的正常行为。
  • 管理命令占用大量内存:一次性遍历大 QuerySet,应使用 iterator() 或分批处理。

八、本篇检查清单

  • 能拆分开发与生产配置并使用环境变量。
  • 理解中间件顺序和请求/响应方向。
  • 知道信号适合附加行为,不隐藏关键业务。
  • 能编写带参数和试运行模式的管理命令。
  • 能用系统检查提前发现关键配置缺失。

上一篇:管理后台定制 | 下一篇:测试、调试与日志