Django配置:开发和生产

  1. 相关配置
    1. 文件结构建议如下:
    2. base.py
    3. dev.py
    4. prod.py
    5. __init__.py
    6. 配置环境变量
      1. 如何生成DJANGO_SECRET_KEY
  2. 相关说明
    1. Django如何区分环境
    2. SECRET_KEY

相关配置

文件结构建议如下:

LinNote/
├── manage.py
├── LinNote/
│   ├── __init__.py
│   ├── asgi.py
│   ├── urls.py
│   ├── wsgi.py
│   └── settings/                 ← 新建 settings 目录
│       ├── __init__.py          ← 自动加载 dev 或 prod
│       ├── base.py              ← 通用配置
│       ├── dev.py               ← 开发环境配置
│       └── prod.py              ← 生产环境配置
├── .venv
├── static/
├── templates/
├── blog/
├── linauth/

base.py

base.py: 放通用配置,所有环境共用

"""
Django settings for LinNote project.

Generated by 'django-admin startproject' using Django 5.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
# BASE_DIR = Path(__file__).resolve().parent.parent
# __file__ :是当前文件的路径,resolve() 方法返回一个绝对路径,parent.parent.parent 是向上三层目录
# 这里的三层目录是为了确保 BASE_DIR 指向项目的根目录,而不是 settings.py 所在的目录
BASE_DIR = Path(__file__).resolve().parent.parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
# SECRET_KEY = "django-insecure-o-tkk1*-9uygums#q9mhk^=g&@kj!+0m+q0#2e_e27k6!3yq#-"

# SECURITY WARNING: don't run with debug turned on in production!
# dev.py/prod.py 会覆盖
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog",  # 添加你的应用
    "linauth",  # 添加你的应用
]

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",
]

ROOT_URLCONF = "LinNote.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

WSGI_APPLICATION = "LinNote.wsgi.application"


# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}


# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]


# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/

STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]  # 确保有这一行

# 这是浏览器访问用户上传文件(如图片、PDF 等)的 URL 前缀。
# 开发阶段:Django 的 runserver 可以处理 /media/ 请求,但需要手动配置 URL(见下文)。
# 生产环境:通常由 Web 服务器(Nginx/Apache)直接托管,Django 不处理。
MEDIA_URL = "/media/"


# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# @login_required 的 重定向 的URL
LOGIN_URL = "/auth/login"

dev.py

dev.py:仅开发用配置,DEBUG=True

# settings/dev.py
from .base import *

DEBUG = True
ALLOWED_HOSTS = ["*"]
# prod.py 会重写
SECRET_KEY = "django-insecure-o-tkk1*-9uygums#q9mhk^=g&@kj!+0m+q0#2e_e27k6!3yq#-"
MEDIA_ROOT = BASE_DIR / "media"  # 用户上传文件的存储目录

prod.py

prod.py:仅生产用配置,DEBUG=False

# settings/prod.py
from .base import *

DEBUG = False
ALLOWED_HOSTS = [
    "linnote.space",
    "www.linnote.space",
    "127.0.0.1",
    "localhost",
    "xx.xxx.xxx.xxx",
]

# 建议用环境变量读取 SECRET_KEY
import os

SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", "")
# 避免项目在缺少 SECRET_KEY 的情况下仍然启动:这样更安全、明确,避免漏配环境变量导致安全隐患
if not SECRET_KEY:
    raise ValueError("DJANGO_SECRET_KEY environment variable not set!")

STATIC_ROOT = BASE_DIR / "staticfiles"

# 这是用户上传文件的存储目录(如 FileField 或 ImageField 上传的文件)。
# 你不需要手动创建它,Django 会在文件上传时自动创建。
MEDIA_ROOT = BASE_DIR / "mediafiles"

# 可选的安全增强配置:
# SECURE_BROWSER_XSS_FILTER 是一个安全设置,用于启用浏览器的 XSS 过滤器。
# XSS(跨站脚本攻击)是一种常见的安全漏洞,攻击者可以通过注入恶意脚本来窃取用户信息或执行其他恶意操作。
SECURE_BROWSER_XSS_FILTER = True
# SECURE_CONTENT_TYPE_NOSNIFF 是一个安全设置,用于防止浏览器猜测内容类型。
# 当启用时,浏览器将严格按照服务器提供的 Content-Type 头部来处理内容,而不是尝试猜测内容类型。
# 这有助于防止某些类型的攻击,例如 MIME 类型混淆攻击。
SECURE_CONTENT_TYPE_NOSNIFF = True
# SECURE_SSL_REDIRECT 是一个安全设置,用于强制将所有 HTTP 请求重定向到 HTTPS。
# 这有助于保护用户数据的安全性,防止中间人攻击。
# 如果你的网站使用 HTTPS,建议将其设置为 True。
SESSION_COOKIE_SECURE = True
# CSRF_COOKIE_SECURE 是一个安全设置,用于确保 CSRF(跨站请求伪造)令牌仅通过 HTTPS 传输。
# CSRF(Cross-Site Request Forgery)是一种攻击方式,攻击者诱使用户在不知情的情况下执行恶意操作。
CSRF_COOKIE_SECURE = True
# SECURE_HSTS_SECONDS 是一个安全设置,用于启用 HTTP 严格传输安全(HSTS)。
# HSTS 是一种安全机制,强制浏览器仅通过 HTTPS 访问网站。
# 当设置为非零值时,浏览器将记住该设置,并在指定的秒数内强制使用 HTTPS。
# 这里设置为 3600 秒(1 小时),可以根据需要调整。
SECURE_HSTS_SECONDS = 3600

__init__.py

__init__.py:自动加载配置(默认 dev,可通过 DJANGO_ENV 切换)

# LinNote/settings/__init__.py

import os

env = os.getenv("DJANGO_ENV", "dev")

if env == "prod":
    print("PROD environment detected, using production settings.")
    from .prod import *
else:
    print("DEV environment detected, using development settings.")
    from .dev import *

配置环境变量

# 将环境变量写入到 bashrc里面
echo "export DJANGO_ENV=prod" >> ~/.bashrc
echo "export DJANGO_SECRET_KEY='your-very-secret-key'" >> ~/.bashrc
source ~/.bashrc

如何生成DJANGO_SECRET_KEY

在终端或 Python shell 中输入:

from django.core.management.utils import get_random_secret_key
print(get_random_secret_key())
# output: l&+fp(e2z=)^7on&n%o2ylcbjgho4*we9@v=mpjc1%9!6b41e9

SECRET_KEY,可以这样设置:

export DJANGO_SECRET_KEY='l&+fp(e2z=)^7on&n%o2ylcbjgho4*we9@v=mpjc1%9!6b41e9'

相关说明

Django如何区分环境

manage.pywsgi.py 中这行代码:

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'LinNote.settings')

告诉 Django 去加载配置模块 LinNote.settings,也就是说它会去找这个 Python 包(不是目录)下的内容。

如果 LinNote/settings 是一个文件夹 + 含 __init__.py,它就是一个 Python 包,Django 就会执行这个包里的 __init__.py 文件,并把其中导入的变量(如 DEBUG, DATABASES, 等)作为配置加载。

所以 __init__.py 的作用是:它作为一个“中转站”,根据你设定的环境变量(如 DJANGO_ENV=prod),动态地导入 dev.pyprod.py 的内容,从而控制加载哪个环境的配置。

# LinNote/settings/__init__.py

import os
### 根据环境变量 DJANGO_ENV 判断现在是开发环境还是生产环境
env = os.getenv("DJANGO_ENV", "dev")

if env == "prod":
    print("PROD environment detected, using production settings.")
    from .prod import *
else:
    print("DEV environment detected, using development settings.")
    from .dev import *

os.getenv("DJANGO_ENV", "dev")方法会获取"DJANGO_ENV"这个变量

  • 在开发环境中不需要设置,因为如果os.getenv获取不到"DJANGO_ENV",就会返回默认值"dev"

  • 在开发环境,就需要做如下配置:

    echo "export DJANGO_ENV=prod" >> ~/.bashrc
    

    这样,就可以区分开发环境了。

SECRET_KEY

SECRET_KEY 是 Django 中用于加密和签名的核心配置,它用于:

  • 主要作用:

    1. 加密 session、cookies 和 CSRF token
    2. 签名密码重置链接
    3. 用于任何 cryptographic signing 的场景
  • 安全警告:

    1. 不能暴露,因为攻击者可以伪造签名;
    2. 不能在不同环境复用,否则测试和生产环境可能互相干扰;
    3. 如果泄露,必须立刻更换并清除原先所有会话等签名数据。

开发环境: 可以使用默认 key。

SECRET_KEY = "django-insecure-o-tkk1*-9uygums#q9mhk^=g&@kj!+0m+q0#2e_e27k6!3yq#-"

生产环境: 应使用独立的、安全性高的 secret key,并确保不要泄露。可以从环境变量读取:

SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", "")
# 避免项目在缺少 SECRET_KEY 的情况下仍然启动:这样更安全、明确,避免漏配环境变量导致安全隐患
if not SECRET_KEY:
    raise ValueError("DJANGO_SECRET_KEY environment variable not set!")

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com

×

喜欢就点赞,疼爱就打赏