Files
Django/a_long_dianjing/settings.py
XingQue 6a107e873d feat: UFO 转盘购票与专区图标(不影响现有俱乐部点单)
新增转盘活动/奖品/机会表与 Czjilu leixing=7 履约;专区 tupian_url;hqsp/详情下发 shi_zhuanpan。普通点单与抢单主链路保持不变。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-22 18:59:26 +08:00

402 lines
14 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 a_long_dianjing project.
"""
from pathlib import Path
from datetime import timedelta
try:
import app_secrets
except ImportError:
raise ImportError("缺少 appapp_secrets.py 密钥配置文件,请参照项目说明创建")
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = app_secrets.SECRET_KEY
DEBUG = False
# 详细错误日志开关True=在 except 块中输出完整堆栈到日志False=仅记录错误摘要
DEBUG_DETAIL_LOG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'www.abas.asia']
# ==================== 应用配置 ====================
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework_simplejwt',
'corsheaders',
'django_celery_results',
'celery',
'gvsdsdk',
'users',
'orders',
'products',
'config',
'backend',
'utils',
'shop',
'rank',
'merchant_ops',
'jituan',
'gongdan',
]
MIDDLEWARE = [
'utils.ip_filter_middleware.IPFilterMiddleware',
'utils.debug_middleware.DebugExceptionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'jituan.middleware.ClubContextMiddleware',
'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',
]
# 日志配置 — 500 错误堆栈输出到 console受 DEBUG_DETAIL_LOG 开关控制
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(asctime)s] %(levelname)s %(name)s: %(message)s'
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'INFO',
},
# 业务模块日志 — DEBUG_DETAIL_LOG=True 时输出 DEBUG 级别(含完整堆栈)
'users': {
'handlers': ['console'],
'level': 'DEBUG' if DEBUG_DETAIL_LOG else 'INFO',
'propagate': False,
},
'orders': {
'handlers': ['console'],
'level': 'DEBUG' if DEBUG_DETAIL_LOG else 'INFO',
'propagate': False,
},
'utils.debug_middleware': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
},
}
ROOT_URLCONF = 'a_long_dianjing.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',
],
},
},
]
WSGI_APPLICATION = 'a_long_dianjing.wsgi.application'
# ==================== 数据库 ====================
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': app_secrets.DATABASE_NAME,
'USER': app_secrets.DATABASE_USER,
'HOST': app_secrets.DATABASE_HOST,
'PASSWORD': app_secrets.DATABASE_PASSWORD,
'PORT': app_secrets.DATABASE_PORT,
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET time_zone='+08:00'",
}
}
}
# ==================== 密码验证 ====================
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'},
]
# ==================== 国际化 ====================
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = False
STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# ==================== JWT 配置 ====================
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=36500),
'REFRESH_TOKEN_LIFETIME': timedelta(days=36500),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': False,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'UserUID',
'USER_ID_CLAIM': 'UserUID',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
'JTI_CLAIM': 'jti',
}
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
]
AUTH_USER_MODEL = 'users.User'
# ==================== DRF 配置 ====================
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'gvsdsdk.auth.jwt_auth.CompatibleJWTAuthentication',
'gvsdsdk.auth.elt_auth.ELTAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/minute',
'user': '1000/minute',
},
'EXCEPTION_HANDLER': 'utils.exception_handler.custom_exception_handler',
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}
# ==================== H5 域名 ====================
H5_DOMAIN = 'https://www.abas.asia:666'
# ==================== CORS 配置 ====================
CORS_ALLOWED_ORIGINS = [
"http://localhost:8080",
"http://127.0.0.1:8080",
"https://www.abas.asia",
"https://www.abas.asia:666",
"https://www.abas.asia:1234",
"https://www.abas.asia:963",
"http://localhost:5174",
"http://localhost:5173",
"http://localhost:3000",
"http://localhost:3001",
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = ("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
CORS_ALLOW_HEADERS = [
"accept", "accept-encoding", "authorization", "content-type",
"dnt", "origin", "user-agent", "x-csrftoken", "x-requested-with",
"x-club-id", "x-club-scope",
]
# ==================== IP 访问控制 ====================
# 访问模式:
# production — 生产模式(默认):放行所有 IP
# whitelist — 白名单模式:仅允许白名单内 IP 访问,其余返回 403
# blacklist — 黑名单模式:禁止黑名单内 IP 访问,其余放行
IP_ACCESS_MODE = 'production'
# 白名单whitelist 模式下生效)— 支持单 IP 和 CIDR 网段
IP_WHITELIST = [
'111.32.64.171',
'43.142.0.208',
'223.104.7.77',
'112.7.200.17'
]
# 黑名单blacklist 模式下生效)— 支持单 IP 和 CIDR 网段
IP_BLACKLIST = []
# 免过滤路径(任何模式下都放行,如管理后台、健康检查)
IP_FILTER_EXEMPT_PATHS = []
# ==================== 腾讯云 COS ====================
COS_SECRET_ID = app_secrets.COS_SECRET_ID
COS_SECRET_KEY = app_secrets.COS_SECRET_KEY
COS_REGION = app_secrets.COS_REGION
COS_BUCKET = app_secrets.COS_BUCKET
COS_SCHEME = 'https'
COS_DOMAIN = f'https://{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com'
COS_APPID = app_secrets.COS_APPID
COS_STS_DURATION = 7200
# ==================== 微信小程序 & 服务号 ====================
WEIXIN_APPID = app_secrets.WEIXIN_APPID
WEIXIN_SECRET = app_secrets.WEIXIN_SECRET
WEIXIN_MCHID = app_secrets.WEIXIN_MCHID
WEIXIN_SHANGHUMIYAO = app_secrets.WEIXIN_SHANGHUMIYAO
WEIXIN_OFFICIAL_APPID = app_secrets.WEIXIN_OFFICIAL_APPID
WEIXIN_OFFICIAL_SECRET = app_secrets.WEIXIN_OFFICIAL_SECRET
WEIXIN_OFFICIAL_TOKEN = app_secrets.WEIXIN_OFFICIAL_TOKEN
WEIXIN_OFFICIAL_ENCODING_AES_KEY = app_secrets.WEIXIN_OFFICIAL_ENCODING_AES_KEY
WEIXIN_TEMPLATE_ID = app_secrets.WEIXIN_TEMPLATE_ID
WEIXIN_TEMPLATE_MAX_PER_MINUTE = 950
WEIXIN_TEMPLATE_BATCH_SIZE = 100
WEIXIN_CERT_PATH = app_secrets.WEIXIN_CERT_PATH
WEIXIN_KEY_PATH = app_secrets.WEIXIN_KEY_PATH
# ==================== 微信支付回调地址 ====================
WEIXIN_NOTIFY_URL = 'https://www.abas.asia/hqhd/dingdan/pay-notify/'
WEIXIN_PAY_DESCRIPTION = "网络服务"
YAJIN_PAY_DESCRIPTION = "打手押金充值"
YAJIN_PAY_NOTIFY_URL = "https://www.abas.asia/hqhd/shangpin/yajinhuitiao"
JIFEN_PAY_DESCRIPTION = "打手积分补充"
JIFEN_PAY_NOTIFY_URL = "https://www.abas.asia/hqhd/shangpin/jifenhuitiao"
HUIYUAN_PAY_DESCRIPTION = "打手会员充值"
HUIYUAN_PAY_NOTIFY_URL = "https://www.abas.asia/hqhd/shangpin/huiyuanhuitiao"
KAOHE_PAY_DESCRIPTION = '考核金牌-缴纳考核费'
KAOHE_PAY_NOTIFY_URL = 'https://www.abas.asia/hqhd/yonghu/kh_huitiao'
KAOHE_PAY_DEFAULT_FEE = 5.00
SHANGJIA_CZ_PREFIX = "CzSJ"
SHANGJIA_CZ_PAY_DESCRIPTION = "阿龙电竞-商家余额充值"
SHANGJIA_CZ_PAY_NOTIFY_URL = "https://www.abas.asia/hqhd/shangpin/sjhuitiao"
SHANGJIA_CZ_MIN_AMOUNT = 1
SHANGJIA_CZ_MAX_AMOUNT = 10000
FAKUAN_PAY_DESCRIPTION = '罚款缴纳'
FAKUAN_PAY_NOTIFY_URL = 'https://www.abas.asia/hqhd/yonghu/fk_huitiao'
ZHUANPAN_PAY_DESCRIPTION = '转盘购票'
ZHUANPAN_PAY_NOTIFY_URL = 'https://www.abas.asia/hqhd/shangpin/zhuanpanhuitiao'
# 支付宝 Czjilu 充值统一回调(会员/押金/积分/商家/考核/罚款)
# 与订单 alipay-notify 分离;密钥仍用 app_secrets.ALIPAY_PROD此处只写死回调地址
ALIPAY_CZJILU_NOTIFY_URL = 'https://www.abas.asia/hqhd/shangpin/alipay-czjilu-notify/'
# ==================== 订单ID前缀 ====================
ORDER_PREFIX = {
'yajin': 'CzYJ',
'jifen': 'CzJF',
'huiyuan': 'CzHY',
}
# ==================== 腾讯云 IM ====================
TENCENT_IM_CONFIG = {
'SDK_APP_ID': 0,
'SECRET_KEY': '',
}
# ==================== 阿里云短信 ====================
ALIYUN_SMS_CONFIG = {
'ACCESS_KEY_ID': '',
'ACCESS_KEY_SECRET': '',
'SIGN_NAME': '',
'TEMPLATE_CODE': '',
'REGION_ID': 'cn-hangzhou',
}
# ==================== GoEasy IM ====================
GOEASY_APPKEY = app_secrets.GOEASY_APPKEY
GOEASY_SECRET = app_secrets.GOEASY_SECRET
GOEASY_REST_URL = 'https://rest-hz.goeasy.io/v2/im/message'
# ==================== Celery 配置 ====================
REDIS_HOST = app_secrets.REDIS_HOST
REDIS_PORT = app_secrets.REDIS_PORT
REDIS_PASSWORD = app_secrets.REDIS_PASSWORD
REDIS_DB_CELERY = app_secrets.REDIS_DB_CELERY
REDIS_DB_RESULT = app_secrets.REDIS_DB_RESULT
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/2',
'TIMEOUT': 300,
'OPTIONS': {}
}
}
if REDIS_PASSWORD:
CELERY_BROKER_URL = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB_CELERY}'
CELERY_RESULT_BACKEND = f'redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB_RESULT}'
else:
CELERY_BROKER_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB_CELERY}'
CELERY_RESULT_BACKEND = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB_RESULT}'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = True
CELERY_IMPORTS = ('orders.notice_tasks',)
CELERY_TASK_TIME_LIMIT = 300
CELERY_TASK_SOFT_TIME_LIMIT = 240
CELERY_WORKER_CONCURRENCY = 4
CELERY_WORKER_PREFETCH_MULTIPLIER = 1
CELERY_TASK_ACKS_LATE = True
CELERY_WORKER_DISABLE_RATE_LIMITS = True
CELERY_TASK_DEFAULT_QUEUE = 'default'
CELERY_TASK_QUEUES = {
'default': {'exchange': 'default', 'routing_key': 'default'},
'order_tasks': {'exchange': 'order_tasks', 'routing_key': 'order_tasks'},
'periodic_tasks': {'exchange': 'periodic_tasks', 'routing_key': 'periodic_tasks'},
}
# ==================== 定时任务时间配置 ====================
# 订单超时自动结算Celery process_expired_order / check_order_expire_task总开关False=彻底关闭
ORDER_AUTO_SETTLEMENT_ENABLED = False
# 打手抢单大厅假单展示False=仅返回真实订单(后台假单管理仍可用;改 True 可恢复假单池)
FAKE_GRAB_ORDER_POOL_ENABLED = False
ORDER_EXPIRE_SECONDS = 48 * 60 * 60 # 48小时 = 172800秒开关关闭时不生效
DAILY_TASK_HOUR = 0
DAILY_TASK_MINUTE = 30
MONTHLY_TASK_DAY = 1
MONTHLY_TASK_HOUR = 0
MONTHLY_TASK_MINUTE = 0
ORDER_CHECK_INTERVAL = 5
# ==================== 微信支付 V3 ====================
WECHAT_PAY_V3_CONFIG = {
'MCHID': '1747846572',
'APPID': 'wx0e4be86faac4a8d1',
'API_V3_KEY': 'dujie4637rufjd98ijuyrgcvbvbn4789',
'PRIVATE_KEY_PATH': app_secrets.WECHAT_PAY_V3_PRIVATE_KEY_PATH,
'CERT_SERIAL_NO': '481784CF56E872D9D8122BAC64E6BC7390803582',
'PLATFORM_CERT_DIR': app_secrets.WECHAT_PAY_V3_PLATFORM_CERT_DIR,
'NOTIFY_URL': 'https://www.abas.asia/hqhd/yonghu/tixiancallback',
'TRANSFER_SCENE_ID': '1005',
}
# ==================== 支付宝支付 ====================
ALIPAY_SANDBOX = app_secrets.ALIPAY_SANDBOX
ALIPAY_PROD = app_secrets.ALIPAY_PROD
ALIPAY_SANDBOX_CFG = app_secrets.ALIPAY_SANDBOX_CFG