393 lines
12 KiB
Python
393 lines
12 KiB
Python
"""
|
||
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"
|
||
|
||
|
||
|