Files
chunyu_project/chunyu_project/settings.py
T
2026-04-05 16:50:12 +08:00

393 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Django settings for chunyu_project project.
Generated by 'django-admin startproject' using Django 6.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
# 安全设置
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
]
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-j+-psq=m++l7hup73k1eg+wm-b&2_)!+_^o=6(=xc$1px*kqt@'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# 生产环境配置
if not DEBUG:
# 从环境变量获取,并过滤空值
cors_env = os.environ.get('CORS_ALLOWED_ORIGINS', '')
if cors_env:
# 解析并验证每个 origin
allowed_origins = []
for origin in cors_env.split(','):
origin = origin.strip()
if origin: # 非空
# 确保有协议(http:// 或 https://)
if not origin.startswith(('http://', 'https://')):
# 自动添加 https://
origin = f'https://{origin}'
allowed_origins.append(origin)
CORS_ALLOWED_ORIGINS = allowed_origins
CORS_ALLOW_ALL_ORIGINS = False
else:
# 如果没有设置,使用默认
CORS_ALLOWED_ORIGINS = []
CORS_ALLOW_ALL_ORIGINS = False
else:
# 开发环境
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOWED_ORIGINS = []
ALLOWED_HOSTS = ["*"]
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", # 例如:您的React/Vue开发服务器
"http://127.0.0.1:3000",
"http://192.168.1.4:3000",
"https://192.168.1.4:3000",
"http://*",
"https://*"
]
# 允许凭据
CORS_ALLOW_CREDENTIALS = True
# 允许的请求头
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
# 允许的 HTTP 方法
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]
CORS_PREFLIGHT_MAX_AGE = 86400
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.SessionAuthentication',
# 如果您不需要标准的TokenAuthentication,可以移除下面这行
# 'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
from datetime import timedelta
# Simple JWT 设置
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), # 访问令牌有效期
'REFRESH_TOKEN_LIFETIME': timedelta(days=7), # 刷新令牌有效期
'ROTATE_REFRESH_TOKENS': True, # 刷新访问令牌时返回新刷新令牌
'BLACKLIST_AFTER_ROTATION': True, # 启用黑名单应用(需安装django-rest-framework-simplejwt.token_blacklist)
'UPDATE_LAST_LOGIN': True, # 更新用户最后登录时间
'ALGORITHM': 'HS256', # 加密算法
'SIGNING_KEY': SECRET_KEY, # 签名密钥,使用您的SECRET_KEY
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('Bearer',), # 认证头前缀,通常是`Bearer`
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id', # 用户模型标识字段
'USER_ID_CLAIM': 'user_id',
}
# 邮件部分
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 使用SMTP
EMAIL_HOST = 'smtp.qq.com' # 需要真实的SMTP服务器
EMAIL_PORT = 465
EMAIL_USE_SSL = True
EMAIL_HOST_USER = 'cs10086086@qq.com' # 真实邮箱账号
EMAIL_HOST_PASSWORD = 'ldzpymytsinkfjhb' # 真实密码/授权码
EMAIL_USE_TLS = False
AUTH_USER_MODEL = 'user.FUser'
INSTALLED_APPS = [
'app.apps.AppConfig',
"user.apps.UserConfig",
"api.apps.ApiConfig",
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
# 第三方应用
'rest_framework',
'rest_framework_simplejwt',
'corsheaders',
'channels',
'django_filters',
'drf_yasg',
'django_extensions',
]
# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'chunyu_project', # 数据库名
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql_NpyMCS', # 数据库密码
'HOST': '192.168.1.4', # 数据库主机,留空默认为localhost
'PORT': '3306', # 数据库端口,留空默认为3306
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'connect_timeout': 10, # 连接超时时间(秒)
},
'CONN_MAX_AGE': 3600, # 连接池最大存活时间(秒),0表示每次请求后关闭
'CONN_HEALTH_CHECKS': True, # 连接健康检查
'ATOMIC_REQUESTS': False, # 是否将每个HTTP请求包装在事务中
'AUTOCOMMIT': True, # 是否自动提交事务
'TIME_ZONE': 'Asia/Shanghai',
}
}
# Redis配置
REDIS_HOST = '192.168.1.4' # Redis服务器地址
REDIS_PORT = 6379 # Redis端口
REDIS_DB = 0 # Redis数据库编号
REDIS_PASSWORD = "+Xy2173240465" # Redis密码,没有密码则设为None
SESSION_DB = 1
CELERY_BROKER_DB = 2
CELERY_RESULT_BACKEND_DB = 2
# Django缓存配置(使用Redis作为缓存后端)
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": REDIS_PASSWORD,
"PARSER_CLASS": "redis.connection._HiredisParser", # 使用hiredis提高性能
'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
'CONNECTION_POOL_CLASS_KWARGS': {
'max_connections': 50,
'timeout': 20,
},
'MAX_CONNECTIONS': 50,
'PICKLE_VERSION': -1,
'SOCKET_CONNECT_TIMEOUT': 5,
'SOCKET_TIMEOUT': 5,
'COMPRESSOR': 'django_redis.compressors.zlib.ZlibCompressor',
'SERIALIZER': 'django_redis.serializers.json.JSONSerializer',
'COMPRESS_MIN_LENGTH': 1024 * 10,
'IGNORE_EXCEPTIONS': True, # 缓存宕机时不崩溃
},
"KEY_PREFIX": "django_", # 缓存键前缀
"VERSION": 1, # 缓存版本
},
'session': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': f"redis://{REDIS_HOST}:{REDIS_PORT}/{SESSION_DB}",
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
},
'celery': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://:password@redis-celery:6379/0',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
# 会话配置
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'session'
SESSION_COOKIE_AGE = 1209600
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
# Celery配置
CELERY_BROKER_URL = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{CELERY_BROKER_DB}'
CELERY_RESULT_BACKEND = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{CELERY_RESULT_BACKEND_DB}'
CELERY_CACHE_BACKEND = 'celery'
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
# 缓存中间件
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 60 * 15
CACHE_MIDDLEWARE_KEY_PREFIX = 'chunyu_site'
# 安全头
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
# 定时任务:预热缓存
CELERY_BEAT_SCHEDULE = {
'warm-up-cache-every-hour': {
'task': 'core.tasks.warm_up_cache',
'schedule': 3600.0, # 每小时
},
'generate-daily-report': {
'task': 'reports.tasks.generate_daily_report',
'schedule': 86400.0, # 每天
},
}
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 60 * 15 # 15分钟
CACHE_MIDDLEWARE_KEY_PREFIX = 'mysite'
ROOT_URLCONF = 'chunyu_project.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
ASGI_APPLICATION = 'chunyu_project.asgi.application'
# 使用Redis作为会话后端
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
# 使用Redis作为消息代理
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
# Password validation
# https://docs.djangoproject.com/en/6.0/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/6.0/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/6.0/howto/static-files/
STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / "staticfiles"