Django-settings详解

这篇讲什么

  • settings.py 能写的键一共 146 个(本机 Django 5.2.19 的 django/conf/global_settings.py 现读,不是抄来的数),这篇先讲清「这些键从哪来、默认值怎么查、改了为什么不生效」,再挑最常碰的四十来个逐条实测,最后给一张 146 条的速查表。
  • 只查某个键的默认值,直接跳「146 条速查表」;正在排「改了 settings 没反应」,先看「改了为什么不生效」。
  • 所有输出都是本机跑出来的(中文 Windows + Python 3.14.10 + Django 5.2.19),报错原文照抄不改字;涉及数据库、邮件、真实域名的部分只做本地沙箱验证,没连任何线上环境。

settings 从哪里来

  • 三层覆盖关系,读源码就一目了然:

    django/conf/__init__.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"

    class LazySettings(LazyObject):
    def _setup(self, name=None):
    """
    Load the settings module pointed to by the environment variable. This
    is used the first time settings are needed, if the user hasn't
    configured settings manually.
    """
    settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
    if not settings_module:
    desc = ("setting %s" % name) if name else "settings"
    raise ImproperlyConfigured(
    "Requested %s, but settings are not configured. "
    "You must either define the environment variable %s "
    "or call settings.configure() before accessing settings."
    % (desc, ENVIRONMENT_VARIABLE)
    )

    self._wrapped = Settings(settings_module)
    • 取值优先级:settings.configure() 传进来的 > 你的 settings 模块 > global_settings.py 里的同名默认值。global_settings 是兜底,你没写的键都从它拿。
    • 模块头部注释也写明了这条路径(实测生成的 settings.py 第 13~17 行):https://docs.djangoproject.com/en/5.2/topics/settings/ 与 .../ref/settings/。
  • 想知道「某个键现在是什么值、默认值是什么」,官方给了现成命令:

    1
    2
    3
    python manage.py diffsettings                  # 只列与内置默认不同的行
    python manage.py diffsettings --all # 列全部(见下面的编码坑)
    python manage.py diffsettings --output unified # 用 -/+ 显示差异

    实测三种输出长这样(同一个刚生成的项目):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    $ manage.py diffsettings
    AUTH_PASSWORD_VALIDATORS = [{'NAME': '...UserAttributeSimilarityValidator'}, {'NAME': '...MinimumLengthValidator'}, ...]
    BASE_DIR = WindowsPath('E:/Desktop/Test/settings-probe/proj') ###
    DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': WindowsPath('.../db.sqlite3'), 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, ...}}
    DEBUG = True
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
    ...
    MY_OWN_KEY = 42 ###
    行数 15

    $ manage.py diffsettings --output unified
    - AUTH_PASSWORD_VALIDATORS = []
    + AUTH_PASSWORD_VALIDATORS = [{'NAME': '...UserAttributeSimilarityValidator'}, ...]
    + BASE_DIR = WindowsPath('E:/Desktop/Test/settings-probe/proj')
    - DEBUG = False
    + DEBUG = True
    + MY_OWN_KEY = 42
    行数 26
    • ### 的含义要分清:默认模式下行尾带 ### 的是「这个键在 Django 内置默认里根本不存在」,也就是你自己加的键(实测 BASE_DIR、ROOT_URLCONF、WSGI_APPLICATION、MY_OWN_KEY 都带它);没带 ### 的行是「键是内置的,但值和你没改时不一样」。
    • --all 会把 146 个键全打出来(实测 150 行:135 行以 ### 开头,表示「这项还是内置默认值」;4 行行尾带 ###,表示「这个键内置默认里没有」,即自定义键;剩下 11 行是你改过的)。
  • 不想跑命令也可以直接读那个模块:

    manage.py shell
    1
    2
    3
    4
    5
    6
    from django.conf import global_settings as g
    len([k for k in dir(g) if k.isupper()]) # 146
    g.SESSION_COOKIE_AGE # 1209600(两周)
    g.CSRF_COOKIE_AGE # 31449600(一年)
    g.DEFAULT_AUTO_FIELD # 'django.db.models.AutoField'
    g.STORAGES.keys() # dict_keys(['default', 'staticfiles'])
    • 注意最后一组:global_settings.DEFAULT_AUTO_FIELD 是 AutoField,而 startproject 生成的 settings.py 里写的是 BigAutoField——「Django 的默认值」和「模板给你的值」是两回事,新项目里是后者。

改了为什么不生效

  • settings 是懒加载的:import django 不会读你的配置文件,第一次访问某个键才去 import。实测:

    1
    2
    3
    4
    读之前 settings.configured  -> False
    读 settings.DEBUG 之后 -> True
    type(settings) -> LazySettings
    type(settings._wrapped) -> Settings
    • configured 是 property 不是方法,写成 settings.configured() 实测报 TypeError: 'bool' object is not callable。
  • 没配置就读、又没设环境变量,报的是这段(实测原文):

    1
    django.core.exceptions.ImproperlyConfigured: Requested setting DEBUG, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
  • 写一个 Django 不认识的键不会报错,它只是没人读而已。实测在 settings.py 末尾加 MY_OWN_KEY = 42 后:

    1
    2
    3
    $ python manage.py check
    System check identified no issues (0 silenced).
    settings.MY_OWN_KEY = 42
    • 反过来,读一个不存在的键是 AttributeError(实测):

      1
      AttributeError: 'Settings' object has no attribute 'NOT_A_REAL_KEY'
    • 所以「键名拼错」和「这个版本没有这个键」都表现为静默无效,diffsettings 里看到它带 ### 就说明 Django 不认识它——这是排查这类问题最快的办法。

  • 列表和字典类设置是整体替换,不是追加(官方在 Core Settings 页专门警告过)。实测只写一个 finder:

    settings.py
    1
    STATICFILES_FINDERS = ["django.contrib.staticfiles.finders.AppDirectoriesFinder"]
    1
    2
    3
    global STATICFILES_FINDERS: [...FileSystemFinder, ...AppDirectoriesFinder]
    只写 AppDirectoriesFinder 后实际启用的 finder: ['AppDirectoriesFinder']
    FileSystemFinder 还在吗: False
    • 同理 INSTALLED_APPS、MIDDLEWARE、TEMPLATES、PASSWORD_HASHERS 都是这样;要保留默认项就自己抄全,或者用「先取默认再拼」的写法:

      settings.py
      1
      2
      3
      from django.conf import global_settings

      STATICFILES_FINDERS = [*global_settings.STATICFILES_FINDERS, "myapp.finders.MyFinder"]
  • override_settings 改不动已经加载的东西。实测两件事:

    1
    2
    进程内 override_settings(USE_I18N=False) + LANGUAGE_CODE=zh-hans -> 后台登录页仍是「用户名/密码/登录」
    新进程里 USE_I18N=False + LANGUAGE_CODE=zh-hans -> 同一页面变回 Username / Password / Log in
    • 结论:翻译表在 setup 时就装好了,override_settings 不会重新加载。测试里要验 USE_I18N、LANGUAGES 这类行为,得另起进程或用 settings.configure() 从头配。
  • DJANGO_SETTINGS_MODULE 与环境变量谁赢:命令行 --settings 赢。实测:

    1
    2
    3
    4
    $ python manage.py check --settings proj.settings_alt
    System check identified no issues (0 silenced).
    最终生效的模块: proj.settings_alt
    ALLOWED_HOSTS(alt 里改过): ['alt.example']
    • 环境变量 DJANGO_SETTINGS_MODULE 只在没给 --settings 时起作用;manage.py 顶部那行 os.environ.setdefault(...) 之所以是 setdefault,就是为了允许外面覆盖。
  • 一个进程只能 configure() 一次(脚本化跑探针时最容易撞):

    1
    2
    第一次 configure 成功
    第二次 configure -> RuntimeError: Settings already configured.
    • 所以要对比两套配置,就得起两个子进程,别在一个进程里来回 configure。

生成的 settings 逐行

  • django-admin startproject proj 生成的 settings.py 一共 123 行,下面按块过一遍(引号风格取决于本机装没装 black:本机装了,所以是双引号;没装就是模板里的单引号)。

    settings.py
    1
    2
    3
    from pathlib import Path

    BASE_DIR = Path(__file__).resolve().parent.parent
    • BASE_DIR 不是配置项(diffsettings 里它带 ### 就是证据),是模板给你算好的路径对象;因为是 pathlib.Path,后面可以直接 BASE_DIR / "db.sqlite3"。
    • 老写法 os.path.join(BASE_DIR, "templates") 也能用,但要先 import os。
    settings.py
    1
    2
    3
    4
    5
    6
    7
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = "django-insecure-ck2a2sl&c8wuq8kvly_#)45hr_*6-yx*-*gujs__2_cbko01#a"

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True

    ALLOWED_HOSTS = []
    • SECRET_KEY 是签名与加密的根钥匙(会话签名、CSRF、signing、密码重置 token 都用它)。空着会在真正用到时报(实测):

      1
      django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
    • 生成值带 django-insecure- 前缀是官方故意留的提醒;生产环境别写进代码库,走环境变量(password 之类的真实值也不要出现在文件里)。

    • SECRET_KEY_FALLBACKS(5.1 起)是给轮换密钥用的:新密钥上线时把旧密钥放进这个列表,旧签名还能验,实测配置能读:

      settings.py
      1
      SECRET_KEY_FALLBACKS = ["old-secret-key"]
    • DEBUG 决定错误页、静态文件由谁服务、模板是否缓存,见下面「基础与调试」。

    • ALLOWED_HOSTS 空列表 + DEBUG=True 时 runserver 只放过本机域名;一旦 DEBUG=False 就全拦(实测):

      1
      2
      3
      Invalid HTTP_HOST header: 'testserver'. You may need to add 'testserver' to ALLOWED_HOSTS.
      django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: 'testserver'. ...
      状态: 400
    • 补上 ALLOWED_HOSTS = ["testserver"] 后同一请求变 404(说明 host 校验过了,只是没这个路由)。

    settings.py
    1
    2
    3
    4
    5
    6
    7
    8
    INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    ]
    • INSTALLED_APPS 的顺序不是装饰:模板与静态文件按这个顺序找,谁在前谁的赢。《Django-站点管理》里 django-admin-interface 必须排在 django.contrib.admin 之前就是这个原因(实测放后面时主题完全不生效,页面 7232 字节 vs 放对 20546 字节)。
    • django.contrib.sites 不在默认列表里,但 SITE_ID 相关的功能(contrib.sites、部分第三方包)会要它。
    settings.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    ]
    • 顺序即请求进入顺序、响应返回顺序(逆序)。细节见《Django-中间件》。
    • SecurityMiddleware 放最前是因为 SECURE_* 那批响应头要在最早加上;CommonMiddleware 要在 CsrfViewMiddleware 之前,APPEND_SLASH 的 301 才不会被 CSRF 先拦掉。
    settings.py
    1
    2
    ROOT_URLCONF = "proj.urls"
    WSGI_APPLICATION = "proj.wsgi.application"
    • 两个都是「点路径字符串」,Django 在需要时才 importlib.import_module。WSGI_APPLICATION 被 gunicorn/uWSGI 引用,见《Django-应用水平扩展》。
    settings.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    TEMPLATES = [
    {
    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "DIRS": [],
    "APP_DIRS": True,
    "OPTIONS": {
    "context_processors": [
    "django.template.context_processors.request",
    "django.contrib.auth.context_processors.auth",
    "django.contrib.messages.context_processors.messages",
    ],
    },
    },
    ]
    • DIRS 空的话项目级模板目录找不到,TEMPLATES 是列表,多引擎共存时按顺序命中;APP_DIRS: True 才会在每个 app 的 templates/ 子目录里找。
    • 子键写错比顶层键写错更常见:context_processors 少写 request 那项,{% csrf_token %} 和 admin 都会出问题;少写 messages 则 messages 模板变量为空。细节见《Django-模板》。
    settings.py
    1
    2
    3
    4
    5
    6
    DATABASES = {
    "default": {
    "ENGINE": "django.db.backends.sqlite3",
    "NAME": BASE_DIR / "db.sqlite3",
    }
    }
    • MySQL/PostgreSQL 的完整写法与驱动选型见《Django-基本入门》《PostgreSQL入门》;DATABASES 的子键(CONN_MAX_AGE、ATOMIC_REQUESTS、OPTIONS、TIME_ZONE、TEST)实测在 diffsettings 里全部展开,形如:

      1
      2
      3
      'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'CONN_HEALTH_CHECKS': False,
      'OPTIONS': {}, 'TIME_ZONE': None, 'USER': '', 'PASSWORD': '', 'HOST': '', 'PORT': '',
      'TEST': {'CHARSET': None, 'COLLATION': None, 'MIGRATE': True, 'MIRROR': None, 'NAME': None}
    • CONN_MAX_AGE 默认 0(每个请求重连),生产常设 60;PASSWORD 走环境变量,不要把明文写进代码。

    settings.py
    1
    2
    3
    4
    5
    6
    LANGUAGE_CODE = "en-us"
    TIME_ZONE = "UTC"
    USE_I18N = True
    USE_TZ = True
    STATIC_URL = "static/"
    DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
    • 这几行的实测行为见下面「国际化与格式」和「基础与调试」。

    • AUTH_PASSWORD_VALIDATORS 默认给了四个校验器(长度、常见密码、纯数字、与用户属性相似),实测把最小长度改成 12 后:

      1
      2
      3
      'short1'         被拦: ['This password is too short. It must contain at least 12 characters.', 'This password is too common.']
      'password' 被拦: ['This password is too short. It must contain at least 12 characters.', 'This password is too common.']
      'Zhang2026!ok' 通过
      • 校验只在 validate_password() / UserCreationForm / admin 建用户时触发,直接 user.set_password() 不会拦,这点见《Django-站点管理》的密码一节。
  • 编码坑(中文 Windows 特有):diffsettings --all 在本机直接崩,因为 LANGUAGES 里有非 GBK 字符(如 Åland):

    1
    UnicodeEncodeError: 'gbk' codec can't encode character '\xe5' in position 5297: illegal multibyte sequence
    • 加 PYTHONIOENCODING=utf-8 再跑就正常(实测 150 行输出)。同理适用于 showmigrations、sqlmigrate 这类会打印大量内置值的命令。

核心配置实测

  • 下面按官方分组过一遍最常碰的键。每条给「默认值 → 改完看到什么」,实测输出都在本机拿的;已经写过专篇的细节只留一句指路,不重复展开。

基础与调试

  • DEBUG(默认 False,模板给 True):开着才有技术性的 404/500 页、才由 Django 自己服务静态文件、模板才每次重新解析。生产必须关,理由见《Django-生产环境中的安全》。

  • INTERNAL_IPS(默认 []):DEBUG=True 时 django.debug 相关能力与第三方调试面板只对列表里的客户端 IP 开,本机一般写 ["127.0.0.1"];django-debug-toolbar 也读它,见《Django-常用插件》。

  • ADMINS / MANAGERS(默认 []):元组列表 [(姓名, 邮箱)]。DEBUG=False 时 500 会发邮件给 ADMINS,404 发给 MANAGERS;发件人是 SERVER_EMAIL。实测配置可读:

    1
    ADMINS 可读 -> ('老板', 'boss@example.com')
  • DEFAULT_EXCEPTION_REPORTER / DEFAULT_EXCEPTION_REPORTER_FILTER:报错的组装者与「哪些字段名要屏蔽」。SECRET_KEY、password 这类是被过滤的默认名单,日志脱敏见《Django-接入监控告警》。

  • DEBUG_PROPAGATE_EXCEPTIONS(默认 False):设 True 后异常直接穿透中间件抛出来,测试里想 assertRaises 就用它。

  • SILENCED_SYSTEM_CHECKS(默认 []):按检查 ID 静默,比如 ["models.W042"]。能静默不等于该静默,先看那条检查说什么。

安全响应头与跳转

  • 实测这一组响应头,全部用 override_settings + 测试客户端拿的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    SECURE_SSL_REDIRECT=True            http 请求 301 / https 请求 200
    SECURE_REDIRECT_EXEMPT=[r"^post/$"] 该路径不跳,http 直接 200
    SECURE_HSTS_SECONDS=3600 + 两个子开关
    Strict-Transport-Security: max-age=3600; includeSubDomains; preload
    且只在 https 响应里出现,http 响应为空
    SECURE_CONTENT_TYPE_NOSNIFF=True X-Content-Type-Options: nosniff
    SECURE_CROSS_ORIGIN_OPENER_POLICY Cross-Origin-Opener-Policy(默认 same-origin)
    X_FRAME_OPTIONS=DENY(默认值) X-Frame-Options: DENY;实测改 SAMEORIGIN 也生效
    SECURE_REFERRER_POLICY Referrer-Policy,默认已是 same-origin
  • SECURE_PROXY_SSL_HEADER(默认 None):站在 Nginx 后面时必须配,否则 Django 看到的是 http,SECURE_SSL_REDIRECT 会和代理互相 301 死循环。实测配上 ("HTTP_X_FORWARDED_PROTO", "https") 后带该头的请求直接 200。

  • USE_X_FORWARDED_HOST / USE_X_FORWARDED_PORT(默认 False):代理改写 Host/Port 时才打开;开了就要保证代理真的覆盖这两个头,否则 ALLOWED_HOSTS 校验会被伪造头绕过。

  • DISALLOWED_USER_AGENTS(默认 []):放正则列表,命中直接 403。实测 [re.compile("BadBot")] 时 User-Agent: BadBot/1 返回 403。

  • IGNORABLE_404_URLS(默认 []):这些 URL 的 404 不给 MANAGERS 发邮件,典型值是 /favicon.ico 和扫描器路径。

  • APPEND_SLASH(默认 True):路径少写斜杠时 301 补上。实测对比很干净:

    1
    2
    APPEND_SLASH=True  GET /post  -> 301,Location: /post/
    APPEND_SLASH=False GET /post -> 404
  • PREPEND_WWW(默认 False):example.com 跳 www.example.com。实测开 True 后对 example.com 的请求返回 301。

  • FORCE_SCRIPT_NAME(默认 None):应用挂在子路径(/mount/point/)下、代理又剥掉了前缀时用它固定 get_script_prefix()。实测设 /mount/ 后 django.get_script_prefix() 就是 /mount/。

CSRF

  • 默认下发 csrftoken cookie,实测属性是 max-age=31449600(一年)、httponly 空(也就是 False)、samesite=Lax、secure 空。逐项改的实测结果:

    1
    2
    3
    4
    5
    CSRF_COOKIE_HTTPONLY=True   -> httponly=True(注意:前端 JS 就取不到 token 了,fetch 方案要改)
    CSRF_COOKIE_NAME="mycsrf" -> cookie 名变 mycsrf
    CSRF_COOKIE_AGE=120 -> max-age=120
    CSRF_COOKIE_SECURE=True -> secure=True(只在 https 下发)
    CSRF_COOKIE_SAMESITE="Strict" -> samesite=Strict
  • CSRF_USE_SESSIONS=True:token 改存 session,实测响应里不再下发 csrftoken cookie,但表单里仍有 csrfmiddlewaretoken 隐藏域。代价是每个请求都要读 session。

  • CSRF_TRUSTED_ORIGINS(默认 []):跨域前端 + 同域后端最容易漏的一项。实测:

    1
    2
    3
    CSRF_TRUSTED_ORIGINS=["http://ok.example"]
    Origin: http://ok.example -> 200
    Origin: http://evil.example -> 403
  • CSRF_COOKIE_DOMAIN / CSRF_COOKIE_PATH:多子域共享 token 时才动,配错的表现是「同域能提交、子域 403」。

  • CSRF_HEADER_NAME(默认 HTTP_X_CSRF_TOKEN_NAME 对应的 X-CSRFToken):前端换自定义头名时改它。

  • CSRF_FAILURE_VIEW(默认 django.views.csrf.csrf_failure):想自定义 403 页面就指到自己的视图。

会话

  • SESSION_ENGINE 五种后端实测都能 round-trip(写一个键再按 session_key 读回来):

    1
    db / cache / cached_db / file / signed_cookies  -> 全部 OK
    • 选法:单机开发用默认 db;多进程/多机用 cache 或 cached_db(Redis 配置见《Django-缓存》);signed_cookies 把数据放进 cookie 本身,体积和敏感信息都受限。
  • cookie 属性实测:默认 sessionid 是 max-age=1209600(两周)、httponly=True、samesite=Lax、secure 空。逐项:

    1
    2
    3
    4
    5
    6
    SESSION_COOKIE_AGE=60                     max-age=60,expires 也跟着推
    SESSION_EXPIRE_AT_BROWSER_CLOSE=True max-age 与 expires 都变空(浏览器会话 cookie)
    SESSION_COOKIE_AGE=60 + EXPIRE_AT_BROWSER 后者优先,仍是会话 cookie
    SESSION_COOKIE_NAME="mysess" cookie 名变 mysess
    SESSION_COOKIE_HTTPONLY=False httponly 变空
    SESSION_COOKIE_SAMESITE="None" + SECURE=True samesite=None 且 secure=True
    • SameSite=None 必须配 SESSION_COOKIE_SECURE=True,否则浏览器会丢弃该 cookie——这是前后端分离项目最常见的「登录后刷新又掉线」原因。
  • SESSION_SAVE_EVERY_REQUEST(默认 False):实测先建 session 再请求一个完全不碰 session 的视图,True 时每次响应都重发 sessionid(等于滑动过期),False 时不重发。

  • SESSION_SERIALIZER(默认 JSON):换成 pickle 会引入反序列化风险,别动。

  • SESSION_CACHE_ALIAS / SESSION_FILE_PATH:分别指定会话用哪个缓存别名、file 后端存哪个目录(默认系统临时目录,生产建议明确写)。

国际化与格式

  • LANGUAGE_CODE(默认 en-us)改成 zh-hans 后,后台登录页文案实测跟着变:

    1
    2
    en-us   label: ['Username:', 'Password:']   value: ['/admin/', 'Log in']
    zh-hans label: ['用户名:', '密码:'] value: ['/admin/', '登录']
  • USE_I18N=False 会关掉翻译,但实测在已启动的进程里用 override_settings 改它不生效(页面仍是中文),新进程里才变回英文:

    1
    新进程 USE_I18N=False + LANGUAGE_CODE=zh-hans -> labels=['Username:', 'Password:'] values=['Log in']
  • LANGUAGES / LANGUAGE_COOKIE_* / LOCALE_PATHS:前者限定可切换语言,中间那组控制语言偏好 cookie,LOCALE_PATHS 放项目自己的 .po/.mo。多语言切换的实现见《Django-模板》。

  • TIME_ZONE(默认 UTC)与 USE_TZ(默认 True)实测:

    1
    2
    TIME_ZONE=Asia/Shanghai 时,UTC 的 2026-11-05 00:00 经 timezone.localtime -> 2026-11-05 08:00:00+08:00
    USE_TZ=False 时 timezone.now().tzinfo -> None
    • 也就是说库里存 UTC、显示按 TIME_ZONE。连 MySQL 时要小心会话时区让 Now() 写进时间列偏 8 小时,这条实测在《Django-环境搭建与版本迁移》里记过。
  • 数字与日期格式有一层优先级,实测很容易踩:

    1
    2
    3
    4
    5
    THOUSAND_SEPARATOR="#" + use_l10n=True  + en       -> 1,234,567.5   (语言包赢)
    THOUSAND_SEPARATOR="#" + use_l10n=False -> 1234567.5 (连分组都没了)
    zh-hans 语言包 + use_l10n=True -> 1234567.5
    DECIMAL_SEPARATOR="," + use_l10n=False -> 1234567,5
    DECIMAL_SEPARATOR="," + use_l10n=True -> 1,234,567.5
    • 结论:use_l10n=True 时语言包优先于 settings,use_l10n=False 才轮到 settings 里的 DECIMAL_SEPARATOR;而 USE_THOUSAND_SEPARATOR 的分组在 use_l10n=False 下并不生效。模板里 {% localize %}、l10n 模板标签与这些行为对应。
    • 自定义格式走 FORMAT_MODULE_PATH(指向一个含 en/、zh_Hans/ 之类包的目录),或者显式 DATE_FORMAT 之类:实测 DATE_FORMAT="Y年m月d日" 配 formats.date_format(d, "DATE_FORMAT", use_l10n=False) 得到 2026年11月05日。
  • FIRST_DAY_OF_WEEK(默认 0)由语言包给值:实测 zh-hans 下 formats.get_format("FIRST_DAY_OF_WEEK", use_l10n=True) 是 1。日历类组件要按它决定周起点。

静态文件与存储

  • STATIC_URL(模板给 static/):只是 URL 前缀,不负责找文件;STATIC_ROOT 是 collectstatic 的输出目录,两者都写进 settings.py 才完整。

  • STATICFILES_DIRS(默认 []):项目级静态目录,写法 BASE_DIR / "static"。

  • STATICFILES_FINDERS:见「改了为什么不生效」,整体替换,实测漏写 FileSystemFinder 后 STATICFILES_DIRS 就失效。

  • STORAGES(4.2 起取代 DEFAULT_FILE_STORAGE / STATICFILES_STORAGE):两个别名 default 与 staticfiles,实测:

    1
    2
    global STORAGES -> {'default': {...FileSystemStorage}, 'staticfiles': {...StaticFilesStorage}}
    把 staticfiles 换成 ManifestStaticFilesStorage 后 staticfiles_storage 类型 -> ManifestStaticFilesStorage
    • 换 Manifest 就必须先 collectstatic,模板里也一律用 {% static %},否则 hash 名对不上直接 404(这条实测在《Django-生产环境要注意哪些事项》里)。
  • MEDIA_URL / MEDIA_ROOT:用户上传文件的 URL 前缀与磁盘目录,DEBUG=False 时 Django 不负责服务它,要交给 Nginx,见《Django-上传文件》。

  • FILE_UPLOAD_HANDLERS / FILE_UPLOAD_MAX_MEMORY_SIZE / FILE_UPLOAD_TEMP_DIR / FILE_UPLOAD_PERMISSIONS / FILE_UPLOAD_DIRECTORY_PERMISSIONS:上传走「内存 → 临时文件」两级,阈值由 FILE_UPLOAD_MAX_MEMORY_SIZE(默认 2.5 MB)决定;实测把它压到 10 字节后,200 字节的上传请求直接 400。

请求体上限

  • 三个 DATA_UPLOAD_* 是 DoS 防护,实测超限都是 400(不是 413):

    1
    2
    3
    DATA_UPLOAD_MAX_NUMBER_FIELDS=2,POST 三个字段   -> 400(默认 1000)
    DATA_UPLOAD_MAX_MEMORY_SIZE=10,body 500 字节 -> 400(默认 2.5 MB)
    DATA_UPLOAD_MAX_NUMBER_FILES(默认 1000) -> 一次请求的文件数上限
    • 表单字段多的后台(几百列的导入页)常撞 NUMBER_FIELDS,报错原文是 SuspiciousOperation: Too many GET/POST parameters,改大它就行,别误判成攻击。

邮件

  • EMAIL_BACKEND 决定邮件去哪,开发期三种最常用:locmem(进 django.core.mail.outbox,实测能断言)、console(打到 stdout)、filebased(落盘 .msg 文件,实测生成 1 个)。

  • DEFAULT_FROM_EMAIL 与 EMAIL_SUBJECT_PREFIX 实测直接体现在发出去的信上:

    1
    2
    DEFAULT_FROM_EMAIL="noreply@example.com" + EMAIL_SUBJECT_PREFIX="[笔记] "
    -> from_email = noreply@example.com | subject = [笔记] 标题
  • SERVER_EMAIL(默认 root@localhost)是系统错误邮件(500/404 给 ADMINS/MANAGERS 的那些)的发件人,很多邮箱会因这个假地址直接拒信。

  • EMAIL_HOST / EMAIL_PORT / EMAIL_HOST_USER / EMAIL_HOST_PASSWORD / EMAIL_USE_TLS / EMAIL_USE_SSL / EMAIL_SSL_CERTFILE / EMAIL_SSL_KEYFILE / EMAIL_TIMEOUT:SMTP 连接参数。password 走环境变量,不要把明文写进代码;EMAIL_USE_TLS(STARTTLS,常见 587)和 EMAIL_USE_SSL(隐式 TLS,常见 465)不要同时开。发送流程与附件写法见《Django-发送邮件》。

  • EMAIL_USE_LOCALTIME(默认 False):邮件头里的时间是否用本地时区。

认证与密码

  • AUTH_USER_MODEL(默认 auth.User):要自定义用户模型必须在第一次 migrate 前改,之后改要处理已有表,细节见《Django-模型》。

  • AUTHENTICATION_BACKENDS(默认 ModelBackend):认证后端链,按顺序试;接 LDAP/OAuth 时往里加。

  • AUTH_PASSWORD_VALIDATORS:实测四个默认校验器 + 自定义 min_length 的效果见「生成的 settings 逐行」。

  • PASSWORD_HASHERS:列表首位就是新密码用的算法。实测临时换成 MD5 后:

    1
    2
    PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"]
    user.set_password("abc") -> 'md5$...$...'(测试跑得快靠这个)
    • 老密码不会自动升级,登录成功时 Django 按列表顺序识别并升级,别把旧算法从列表里删掉。
  • PASSWORD_RESET_TIMEOUT(默认 2592000 秒,即 3 天):重置 token 的有效期。

  • LOGIN_URL / LOGIN_REDIRECT_URL / LOGOUT_REDIRECT_URL:实测未登录访问 /admin/ 返回 302 且 Location 指向登录页。@login_required 读 LOGIN_URL,admin 用自己的。

数据库与缓存

  • DATABASES 的完整子键在 diffsettings 里能一次看全(实测展开见「生成的 settings 逐行」)。CONN_MAX_AGE 默认 0,CONN_HEALTH_CHECKS 默认 False,长连接池场景两个一起配。

  • DATABASE_ROUTERS(默认 []):多库读写分离/分库的路由类列表。

  • DEFAULT_AUTO_FIELD:实测不配时 check 报:

    1
    2
    autocheckapp.Item: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.
    HINT: Configure the DEFAULT_AUTO_FIELD setting or the AutocheckappConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.
    • 配上 BigAutoField 后 System check identified no issues (0 silenced).。优先级是 AppConfig 的 default_auto_field > settings 的 DEFAULT_AUTO_FIELD > 内置 AutoField。
  • CACHES:默认只有一个 default,后端是 LocMemCache(进程内,多进程不共享,实测踩过)。Redis 后端的写法与失效策略见《Django-缓存》。

  • CACHE_MIDDLEWARE_ALIAS / _SECONDS / _KEY_PREFIX:UpdateCacheMiddleware 用哪份缓存、默认 TTL、key 前缀。

  • TEST_RUNNER(默认 DiscoverRunner)、TEST_NON_SERIALIZED_APPS、FIXTURE_DIRS、MIGRATION_MODULES:测试与迁移相关的四个,日常改得少,MIGRATION_MODULES 还能指向 None 来禁用某 app 的迁移。

  • DEFAULT_TABLESPACE / DEFAULT_INDEX_TABLESPACE:非默认表空间才需要,本机未验证(默认 None)。

模板与表单

  • TEMPLATES 是列表,每个引擎的 OPTIONS 里 context_processors、debug、loaders、string_if_invalid 都能配;实测把 string_if_invalid 设成标记串后,模板里取不到的变量会直接把标记渲染出来,排查变量名拼错很好用(见《Django-模板》)。

  • FORM_RENDERER(默认 DjangoTemplates,走 django/forms/templates):实测换成 DjangoDivFormRenderer 后,str(form) 的外层从 <ul> 变 <div>:

    1
    FORM_RENDERER="django.forms.renderers.DjangoDivFormRenderer" -> <div>...(无 <ul>)
  • FORMS_URLFIELD_ASSUME_HTTPS(默认 False):URLField 对 scheme 的处理开关,5.x 过渡项, transitional 用。

  • MESSAGE_STORAGE(默认 FallbackStorage,先 session 后 cookie):实测改成 CookieStorage 后配置值直接可读,无 session 的项目常用它。

  • ABSOLUTE_URL_OVERRIDES(默认 {}):不给模型写 get_absolute_url,改在这里按 app_label.ModelName 配函数。

日志

  • LOGGING_CONFIG(默认 logging.config.dictConfig)与 LOGGING:LOGGING 是标准 dict 配置,disable_existing_loggers 忘写会静默掉 Django 自己的 logger。写法与落盘见《Django-生产环境要注意哪些事项》。

146 条速查表

  • 默认值这一列全部由 django.conf.global_settings(Django 5.2.19)现读,不是抄文档;列表和字典只给项数与首项/键名。
  • 用法列只写「这个键管什么」,具体行为与实测在上面「核心配置实测」一节。
键 类型 默认值(本机现读) 一句话用途
ABSOLUTE_URL_OVERRIDES dict {}(空字典) 不给模型写 get_absolute_url,按 app_label.ModelName 配函数
ADMINS list [](空列表) 500 错误邮件的收件人列表
ALLOWED_HOSTS list [](空列表) 允许的 Host 头(域名白名单)
APPEND_SLASH bool True 路径少写斜杠时是否 301 补上
AUTHENTICATION_BACKENDS list 1 项,首项 'django.contrib.auth.backends.Mode… 认证后端链,按顺序试
AUTH_PASSWORD_VALIDATORS list [](空列表) 密码强度校验器列表
AUTH_USER_MODEL str ‘auth.User’ 自定义用户模型,首次 migrate 前定死
CACHES dict 1 键:default 缓存后端与别名
CACHE_MIDDLEWARE_ALIAS str ‘default’ 缓存中间件用哪个缓存别名
CACHE_MIDDLEWARE_KEY_PREFIX str ‘’ 缓存中间件的 key 前缀
CACHE_MIDDLEWARE_SECONDS int 600 缓存中间件的默认 TTL
CSRF_COOKIE_AGE int 31449600 csrftoken cookie 有效期
CSRF_COOKIE_DOMAIN NoneType None csrftoken 的域
CSRF_COOKIE_HTTPONLY bool False csrftoken 是否禁止 JS 读取
CSRF_COOKIE_NAME str ‘csrftoken’ csrftoken 的 cookie 名
CSRF_COOKIE_PATH str ‘/’ csrftoken 的 cookie 路径
CSRF_COOKIE_SAMESITE str ‘Lax’ csrftoken 的 SameSite
CSRF_COOKIE_SECURE bool False csrftoken 是否只在 HTTPS 下发
CSRF_FAILURE_VIEW str ‘django.views.csrf.csrf_failure’ CSRF 校验失败时渲染的视图
CSRF_HEADER_NAME str ‘HTTP_X_CSRFTOKEN’ 从哪个请求头读 CSRF token
CSRF_TRUSTED_ORIGINS list [](空列表) 可信的 Origin 列表(跨域前端必配)
CSRF_USE_SESSIONS bool False CSRF token 改存 session,不发 cookie
DATABASES dict {}(空字典) 数据库别名与连接参数
DATABASE_ROUTERS list [](空列表) 多库/读写分离的路由类
DATA_UPLOAD_MAX_MEMORY_SIZE int 2621440 请求体大小上限(非文件部分)
DATA_UPLOAD_MAX_NUMBER_FIELDS int 1000 GET/POST 参数个数上限
DATA_UPLOAD_MAX_NUMBER_FILES int 100 一次请求的文件数上限
DATETIME_FORMAT str ‘N j, Y, P’ 日期时间的默认显示格式
DATETIME_INPUT_FORMATS list 9 项,首项 ‘%Y-%m-%d %H:%M:%S’ 表单解析日期时间的候选格式
DATE_FORMAT str ‘N j, Y’ 日期的默认显示格式
DATE_INPUT_FORMATS list 11 项,首项 ‘%Y-%m-%d’ 表单解析日期的候选格式
DEBUG bool False 调试模式,生产必须 False
DEBUG_PROPAGATE_EXCEPTIONS bool False 让异常穿透中间件,测试断言用
DECIMAL_SEPARATOR str ‘.’ 小数点字符
DEFAULT_AUTO_FIELD str ‘django.db.models.AutoField’ 模型默认自增主键类型
DEFAULT_CHARSET str ‘utf-8’ HTTP 响应的字符集
DEFAULT_EXCEPTION_REPORTER str ‘django.views.debug.ExceptionReporter’ 500 报错的组装者
DEFAULT_EXCEPTION_REPORTER_FILTER str 'django.views.debug.SafeExceptionRepo… 报错里要屏蔽的敏感字段
DEFAULT_FROM_EMAIL str ‘webmaster@localhost’ send_mail 默认发件人
DEFAULT_INDEX_TABLESPACE str ‘’ 建索引的默认表空间
DEFAULT_TABLESPACE str ‘’ 建表的默认表空间
DISALLOWED_USER_AGENTS list [](空列表) 命中的 User-Agent 直接 403
EMAIL_BACKEND str 'django.core.mail.backends.smtp.Email… 邮件后端类(发真信/只收集/落盘)
EMAIL_HOST str ‘localhost’ SMTP 服务器地址
EMAIL_HOST_PASSWORD str ‘’ SMTP 密码(走环境变量)
EMAIL_HOST_USER str ‘’ SMTP 用户名
EMAIL_PORT int 25 SMTP 端口(25/465/587)
EMAIL_SSL_CERTFILE NoneType None SMTPS 客户端证书
EMAIL_SSL_KEYFILE NoneType None SMTPS 客户端私钥
EMAIL_SUBJECT_PREFIX str '[Django] ’ 邮件主题前缀
EMAIL_TIMEOUT NoneType None SMTP 连接超时秒数
EMAIL_USE_LOCALTIME bool False 邮件头时间是否用本地时区
EMAIL_USE_SSL bool False 隐式 TLS(常见 465)
EMAIL_USE_TLS bool False STARTTLS(常见 587)
FILE_UPLOAD_DIRECTORY_PERMISSIONS NoneType None 上传时新建目录的权限
FILE_UPLOAD_HANDLERS list 2 项,首项 'django.core.files.uploadhandler.M… 上传处理器链(内存/临时文件)
FILE_UPLOAD_MAX_MEMORY_SIZE int 2621440 超过就转临时文件的阈值
FILE_UPLOAD_PERMISSIONS int 420 上传文件的权限位
FILE_UPLOAD_TEMP_DIR NoneType None 上传临时文件目录
FIRST_DAY_OF_WEEK int 0 一周的第一天(语言包会给值)
FIXTURE_DIRS list [](空列表) 加载测试数据的额外目录
FORCE_SCRIPT_NAME NoneType None 强制 URL 前缀(挂在子路径时)
FORMAT_MODULE_PATH NoneType None 自定义格式模块所在的包
FORMS_URLFIELD_ASSUME_HTTPS bool False URLField 是否默认补 https
FORM_RENDERER str ‘django.forms.renderers.DjangoTemplates’ 表单渲染器类
IGNORABLE_404_URLS list [](空列表) 这些 URL 的 404 不给 MANAGERS 发邮件
INSTALLED_APPS list [](空列表) 安装的应用(顺序影响模板与静态查找)
INTERNAL_IPS list [](空列表) 调试能力只对哪些客户端 IP 开
LANGUAGES list 99 项,首项 ‘af’ 可切换的语言列表
LANGUAGES_BIDI list 7 项,首项 ‘he’ 从右往左书写的语言
LANGUAGE_CODE str ‘en-us’ 默认语言
LANGUAGE_COOKIE_AGE NoneType None 语言偏好 cookie 有效期
LANGUAGE_COOKIE_DOMAIN NoneType None 语言偏好 cookie 的域
LANGUAGE_COOKIE_HTTPONLY bool False 语言偏好 cookie 是否禁 JS 读
LANGUAGE_COOKIE_NAME str ‘django_language’ 语言偏好 cookie 名
LANGUAGE_COOKIE_PATH str ‘/’ 语言偏好 cookie 路径
LANGUAGE_COOKIE_SAMESITE NoneType None 语言偏好 cookie 的 SameSite
LANGUAGE_COOKIE_SECURE bool False 语言偏好 cookie 是否仅 HTTPS
LOCALE_PATHS list [](空列表) 项目自己的翻译文件目录
LOGGING dict {}(空字典) 日志配置字典
LOGGING_CONFIG str ‘logging.config.dictConfig’ 应用 LOGGING 用的函数
LOGIN_REDIRECT_URL str ‘/accounts/profile/’ 登录后的默认跳转
LOGIN_URL str ‘/accounts/login/’ 未登录时 @login_required 跳哪
LOGOUT_REDIRECT_URL NoneType None 登出后的跳转
MANAGERS list [](空列表) 404 错误邮件的收件人列表
MEDIA_ROOT str ‘’ 用户上传文件的根目录
MEDIA_URL str ‘’ 用户上传文件的 URL 前缀
MESSAGE_STORAGE str 'django.contrib.messages.storage.fall… 消息存储类
MIDDLEWARE list [](空列表) 中间件链(顺序即执行顺序)
MIGRATION_MODULES dict {}(空字典) 指定 app 的迁移模块,可为 None 禁用
MONTH_DAY_FORMAT str ‘F j’ 月日格式
NUMBER_GROUPING int 0 千分位分组长度
PASSWORD_HASHERS list 5 项,首项 'django.contrib.auth.hashers.PBKDF… 密码哈希算法优先级
PASSWORD_RESET_TIMEOUT int 259200 重置 token 的有效期
PREPEND_WWW bool False 自动跳到 www. 前缀
SECRET_KEY str ‘’ 签名与加密的根钥匙
SECRET_KEY_FALLBACKS list [](空列表) 轮换密钥期间兼容的旧密钥
SECURE_CONTENT_TYPE_NOSNIFF bool True 加 X-Content-Type-Options 头
SECURE_CROSS_ORIGIN_OPENER_POLICY str ‘same-origin’ 加 Cross-Origin-Opener-Policy 头
SECURE_HSTS_INCLUDE_SUBDOMAINS bool False HSTS 是否覆盖子域
SECURE_HSTS_PRELOAD bool False HSTS 是否带 preload 标记
SECURE_HSTS_SECONDS int 0 HSTS 时长(仅 HTTPS 响应出现)
SECURE_PROXY_SSL_HEADER NoneType None 认代理传来的协议头
SECURE_REDIRECT_EXEMPT list [](空列表) 这些路径不做 HTTPS 跳转
SECURE_REFERRER_POLICY str ‘same-origin’ Referrer-Policy 头
SECURE_SSL_HOST NoneType None 强制跳转的目标域名
SECURE_SSL_REDIRECT bool False 非 HTTPS 一律 301
SERVER_EMAIL str ‘root@localhost’ 系统错误邮件的发件人
SESSION_CACHE_ALIAS str ‘default’ 会话用哪个缓存别名
SESSION_COOKIE_AGE int 1209600 会话 cookie 有效期
SESSION_COOKIE_DOMAIN NoneType None 会话 cookie 的域
SESSION_COOKIE_HTTPONLY bool True 会话 cookie 是否禁止 JS 读
SESSION_COOKIE_NAME str ‘sessionid’ 会话 cookie 名
SESSION_COOKIE_PATH str ‘/’ 会话 cookie 路径
SESSION_COOKIE_SAMESITE str ‘Lax’ 会话 cookie 的 SameSite
SESSION_COOKIE_SECURE bool False 会话 cookie 是否仅 HTTPS
SESSION_ENGINE str ‘django.contrib.sessions.backends.db’ 会话存储后端(5 种)
SESSION_EXPIRE_AT_BROWSER_CLOSE bool False 关浏览器即过期
SESSION_FILE_PATH NoneType None file 后端的存放目录
SESSION_SAVE_EVERY_REQUEST bool False 每次请求都重发会话 cookie
SESSION_SERIALIZER str 'django.contrib.sessions.serializers.… 会话序列化器
SHORT_DATETIME_FORMAT str ‘m/d/Y P’ 短日期时间格式
SHORT_DATE_FORMAT str ‘m/d/Y’ 短日期格式
SIGNED_COOKIE_LEGACY_SALT_FALLBACK bool True 是否兼容旧的签名 salt
SIGNING_BACKEND str ‘django.core.signing.TimestampSigner’ 签名实现类
SILENCED_SYSTEM_CHECKS list [](空列表) 按 ID 静默系统检查
STATICFILES_DIRS list [](空列表) 项目级静态文件目录
STATICFILES_FINDERS list 2 项,首项 'django.contrib.staticfiles.finder… 静态文件查找器(整体替换)
STATIC_ROOT NoneType None collectstatic 的输出目录
STATIC_URL NoneType None 静态文件的 URL 前缀
STORAGES dict 2 键:default, staticfiles 默认存储与静态存储(4.2 起)
TEMPLATES list [](空列表) 模板引擎配置列表
TEST_NON_SERIALIZED_APPS list [](空列表) 并行测试时不序列化的 app
TEST_RUNNER str ‘django.test.runner.DiscoverRunner’ 跑测试的入口类
THOUSAND_SEPARATOR str ‘,’ 千分位字符
TIME_FORMAT str ‘P’ 时间格式
TIME_INPUT_FORMATS list 3 项,首项 ‘%H:%M:%S’ 表单解析时间的候选格式
TIME_ZONE str ‘America/Chicago’ 项目时区(显示用)
USE_I18N bool True 是否启用翻译
USE_THOUSAND_SEPARATOR bool False 是否分组显示数字
USE_TZ bool True 存 UTC、按 TIME_ZONE 显示
USE_X_FORWARDED_HOST bool False 是否认 X-Forwarded-Host
USE_X_FORWARDED_PORT bool False 是否认 X-Forwarded-Port
WSGI_APPLICATION NoneType None WSGI 入口的点路径
X_FRAME_OPTIONS str ‘DENY’ X-Frame-Options 的值
YEAR_MONTH_FORMAT str ‘F Y’ 年月格式

新手卡点清单

  • 都是实测踩过的:

    卡点 症状(实测原文) 正确做法
    键名拼错或这版没这键 不报错、不生效;diffsettings 里该行带 ### 用 diffsettings / global_settings 对一遍,别猜
    列表类设置只写自己那项 STATICFILES_DIRS 突然失效(实测 FileSystemFinder 消失) 从 global_settings 拷全再追加
    改 USE_I18N 用 override_settings 页面仍是中文(实测),新进程才变英文 翻译类改动另起进程验证
    INSTALLED_APPS 顺序随意 django-admin-interface 放 admin 之后主题完全不生效(实测 7232 vs 20546 字节) 要覆盖 admin 模板的包排在 django.contrib.admin 之前
    没配 SECRET_KEY ImproperlyConfigured: The SECRET_KEY setting must not be empty. 生成项目就带上,生产走环境变量
    DEBUG=False 没配 ALLOWED_HOSTS DisallowedHost: Invalid HTTP_HOST header... + 响应 400 上线前把域名(含 .example.com 通配)写全
    SameSite=None 没配 Secure 浏览器丢弃 cookie,登录态刷新就掉 SESSION_COOKIE_SAMESITE="None" 必须配 SESSION_COOKIE_SECURE=True
    前端 JS 取不到 CSRF token 设了 CSRF_COOKIE_HTTPONLY=True 后 fetch 报 403 要么别开 HttpOnly,要么改用 session 存 token / 隐藏域
    跨域前端提交表单 403 Origin: http://evil.example -> 403(实测可信源才 200) 把前端源写进 CSRF_TRUSTED_ORIGINS(要带 scheme)
    表单字段特别多报 400 Too many GET/POST parameters(实测阈值 2 时三字段就 400) 调 DATA_UPLOAD_MAX_NUMBER_FIELDS,不是 Django 坏了
    数字分隔符改了不生效 use_l10n=True 下语言包赢(实测 # 被忽略) 要 settings 说话就用 use_l10n=False 或 FORMAT_MODULE_PATH
    模型没写主键类型 models.W042 警告(实测原文见上) 配 DEFAULT_AUTO_FIELD 或 AppConfig 的 default_auto_field
    diffsettings --all 崩 UnicodeEncodeError: 'gbk' codec can't encode character '\xe5' 加 PYTHONIOENCODING=utf-8(中文 Windows 特有)
    一个进程里反复 configure() RuntimeError: Settings already configured. 每套配置起一个子进程
    以为 settings.configured() 是方法 TypeError: 'bool' object is not callable 它是 property,不带括号
    生产开着 DEBUG 500 页把 settings、SQL、请求头全摊开 DEBUG=False + 正确的 ALLOWED_HOSTS
    明文密码写进 settings 提交进仓库就泄露 password 一律走环境变量,代码里只留键名

参考