2025-03-18 08:46:50 +08:00

566 lines
20 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 application project.
Generated by 'django-admin startproject' using Django 4.1.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""
import os
import sys
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
sys.path.insert(1, os.path.join(BASE_DIR, 'extra_apps'))
# ================================================= #
# ******************** 动态配置 ******************** #
# ================================================= #
from config import *
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-n=y=uyd%&wkwegt37+ulo_-0j_isd@f@q8p+1xan@qcff8a!kvp*'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = locals().get("DEBUG", False)
ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#other app
# 'channels',#websocket
'django_comment_migrate',
'rest_framework',
'django_filters',
'corsheaders',#允许跨域
'drf_yasg',#在线接口文档
'captcha',#验证码
'django_celery_results',
'django_celery_beat',#计划任务
#myown app
'mysystem',
#custom app
'apps.lymessages',
'apps.address',
'apps.oauth',
'apps.logins',
'apps.lyusers',
'apps.platformsettings',
'apps.mall',
'apps.lymonitor',
'apps.lywebsocket',
'apps.lycrontab',
'apps.lyautocode',
'apps.lyFormBuilder',
'apps.lyTiktokUnion',
'apps.lyworkflow',
]
MIDDLEWARE = [
'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',
'utils.middleware.ApiLoggingMiddleware',#自定义日志中间件
]
ROOT_URLCONF = 'application.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'frontend')]#放置前端页面的地方
,
'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',
],
},
},
]
ASGI_APPLICATION = 'application.asgi.application'
WSGI_APPLICATION = 'application.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
#sqlite3
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
# }
#mysql
DATABASES = {
'default': {
'ENGINE': DATABASE_ENGINE,
'NAME': DATABASE_NAME,
'USER': DATABASE_USER,
'PASSWORD': DATABASE_PASSWORD,
'HOST': DATABASE_HOST,
'PORT': DATABASE_PORT,
'CONN_MAX_AGE':DATABASE_CONN_MAX_AGE,
'OPTIONS': {
'charset':DATABASE_CHARSET,
'init_command': 'SET default_storage_engine=INNODB', #innodb才支持事务
}
}
}
AUTH_USER_MODEL = 'mysystem.Users'
USERNAME_FIELD = 'username'
ALL_MODELS_OBJECTS = [] # 所有app models 对象
# 配置redis缓存
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache', # 缓存后端 Redis
# 连接Redis数据库(服务器地址)
# 一主带多从(可以配置多个Redis写走第一台读走其他的机器)
'LOCATION': [
f'{REDIS_URL}/0',
],
'KEY_PREFIX': 'lybbn', # 项目名当做文件前缀
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', # 连接选项(默认,不改)
'CONNECTION_POOL_KWARGS': {
'max_connections': 512, # 连接池的连接(最大连接)
},
}
},
'session': { #缓存session
'BACKEND': 'django_redis.cache.RedisCache', # 缓存后端 Redis
# 连接Redis数据库(服务器地址)
# 一主带多从(可以配置多个Redis写走第一台读走其他的机器)
'LOCATION': [
f'{REDIS_URL}/1',
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', # 连接选项(默认,不改)
}
},
'verify_codes': { #缓存短信验证码
'BACKEND': 'django_redis.cache.RedisCache', # 缓存后端 Redis
# 连接Redis数据库(服务器地址)
# 一主带多从(可以配置多个Redis写走第一台读走其他的机器)
'LOCATION': [
f'{REDIS_URL}/2',
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', # 连接选项(默认,不改)
}
},
"carts": { #登陆过的用户购物车的存储
"BACKEND": "django_redis.cache.RedisCache",
'LOCATION': [
f'{REDIS_URL}/3',
],
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
'CONNECTION_POOL_KWARGS': {'decode_responses': True}, # 添加这一行,防止取出的值带有b'' bytes
},
},
"authapi": { # 接口安全校验(验证接口重复第二次访问会拒绝)
'BACKEND': 'django_redis.cache.RedisCache', # 缓存后端 Redis
# 连接Redis数据库(服务器地址)
# 一主带多从(可以配置多个Redis写走第一台读走其他的机器)
'LOCATION': [
f'{REDIS_URL}/4',
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', # 连接选项(默认,不改)
}
},
"singletoken": { # jwt单用户登录确保一个账户只有一个地点登录后一个会顶掉前一个
'BACKEND': 'django_redis.cache.RedisCache', # 缓存后端 Redis
# 连接Redis数据库(服务器地址)
# 一主带多从(可以配置多个Redis写走第一台读走其他的机器)
'LOCATION': [
f'{REDIS_URL}/5',
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient', # 连接选项(默认,不改)
'CONNECTION_POOL_KWARGS': {'decode_responses': True}, # 添加这一行,防止取出的值带有b'' bytes
}
},
}
REDIS_TIMEOUT = 7 * 24 * 60 * 60
CUBES_REDIS_TIMEOUT = 60 * 60
NEVER_REDIS_TIMEOUT = 365 * 24 * 60 * 60
CHANNEL_LAYERS = {
'default': {
"BACKEND": "channels.layers.InMemoryChannelLayer" # 默认用内存
},
}
# # 配置channels_rediswindows redis运行后报错aioredis.errors.ReplyError: ERR unknown command 'BZPOPMIN'请注释以下配置或升级redis到5.0及以上
# CHANNEL_LAYERS = {
# 'default': {
# 'BACKEND': 'channels_redis.core.RedisChannelLayer',
# 'CONFIG': {
# "hosts": ["redis://localhost:6379/5"],
# },
# },
# }
# session使用的存储方式
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# 指明使用哪一个库保存session数据
SESSION_CACHE_ALIAS = "session"
# Password validation
# https://docs.djangoproject.com/en/3.2/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/3.2/topics/i18n/
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False#设置为中国时间
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# 设置django的静态文件目录
# STATICFILES_DIRS = [
# os.path.join(BASE_DIR, "static"),
# ]
FRONTEND_ROOT = os.path.join(BASE_DIR, "frontend")
STATICFILES_DIRS = [
os.path.join(FRONTEND_ROOT,"static"),
os.path.join(FRONTEND_ROOT,"download-app","static"),
os.path.join(FRONTEND_ROOT,"h5","static"),
]
# 收集静态文件,必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
# python manage.py collectstatic
STATIC_ROOT=os.path.join(BASE_DIR,'static')
# 访问上传文件的url地址前缀
if not os.path.exists(os.path.join(BASE_DIR, 'media')):
os.makedirs(os.path.join(BASE_DIR, 'media'))
MEDIA_URL = "/media/"
# 项目中存储上传文件的根目录
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# ================================================= #
# ******************** 自定义权限 ******************** #
# ================================================= #
AUTHENTICATION_BACKENDS = ["utils.customBackend.CustomBackend"]
# ================================================= #
# ******************* 跨域的配置 ******************* #
# ================================================= #
# 如果为True则将不使用白名单并且将接受所有来源。默认为False
#允许跨域
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_ALL_ORIGINS = True #新版 ACCESS_CONTROL_ALLOW_ORIGIN = '*' ,不能与CORS_ALLOW_CREDENTIALS一起使用
# 允许cookie
# CORS_ALLOW_CREDENTIALS = True # 指明在跨域访问中后端是否支持对cookie的操作
SECURE_CROSS_ORIGIN_OPENER_POLICY = 'None'
X_FRAME_OPTIONS = 'SAMEORIGIN'#SAMEORIGIN允许同源iframe嵌套、 DENY不允许iframe、ALLOW-FROM http://xxx.com指定uri嵌套、ALLOWALL 允许所有域名嵌套
# 允许的header头部字段
# CORS_ALLOW_HEADERS = (
# "accept",
# "authorization",
# "content-type",
# "user-agent",
# "x-csrftoken",
# "x-requested-with",
# "accept-encoding",
# "lypage"
# )
# ================================================= #
# ********************* 日志配置 ******************* #
# ================================================= #
# log 配置部分BEGIN #
SERVER_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'server.log')
ERROR_LOGS_FILE = os.path.join(BASE_DIR, 'logs', 'error.log')
if not os.path.exists(os.path.join(BASE_DIR, 'logs')):
os.makedirs(os.path.join(BASE_DIR, 'logs'))
# 格式:[2023-12-28 20:45:03][basehttp.py:187:log_message] [INFO] 这是一条日志:
# 格式:[日期][文件名:行号:函数] [级别] 信息
STANDARD_LOG_FORMAT = '[%(asctime)s][%(filename)s:%(lineno)d:%(funcName)s] [%(levelname)s] %(message)s'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': STANDARD_LOG_FORMAT,
'datefmt': '%Y-%m-%d %H:%M:%S',
},
'console': {
'format': STANDARD_LOG_FORMAT,
'datefmt': '%Y-%m-%d %H:%M:%S',
},
'file': {
'format': STANDARD_LOG_FORMAT,
'datefmt': '%Y-%m-%d %H:%M:%S',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': SERVER_LOGS_FILE,
'maxBytes': 1024 * 1024 * 10, # 10 MB
'backupCount': 10, # 最多备份10个
'formatter': 'standard',
'encoding': 'utf-8',
},
'error': {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler',
'filename': ERROR_LOGS_FILE,
'maxBytes': 1024 * 1024 * 10, # 10 MB
'backupCount': 10, # 最多备份10个
'formatter': 'standard',
'encoding': 'utf-8',
},
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'console',
}
},
'loggers': {
# default日志
'': {
'handlers': ['console', 'error', 'file'],
'level': 'INFO',
},
'django': {
'handlers': ['console', 'error', 'file'],
'level': 'INFO',
"propagate": False,# 不向上级 logger 传播
},
'scripts': {
'handlers': ['console', 'error', 'file'],
'level': 'INFO',
},
# 数据库相关日志
'django.db.backends': {
'handlers': ["console", "error", "file"],
'propagate': False,
'level': 'INFO',
},
"uvicorn.error": {
"level": "INFO",
"handlers": ["console", "error", "file"],
},
"uvicorn.access": {
"handlers": ["console", "error", "file"],
"level": "INFO"
},
}
}
# ================================================= #
# *************** REST_FRAMEWORK配置 *************** #
# ================================================= #
REST_FRAMEWORK = {
'DATETIME_FORMAT': "%Y-%m-%d %H:%M:%S", # 日期时间格式配置
'DATE_FORMAT': "%Y-%m-%d",
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
),
'DEFAULT_PAGINATION_CLASS': 'utils.pagination.CustomPagination', # 自定义分页
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
# 'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
#限速设置
# 'DEFAULT_THROTTLE_CLASSES': (
# 'rest_framework.throttling.AnonRateThrottle', #未登陆用户
# 'rest_framework.throttling.UserRateThrottle' #登陆用户
# ),
# 'DEFAULT_THROTTLE_RATES': {
# 'anon': '30/minute', #未登录用户每分钟可以请求30次还可以设置'100/day',天数
# 'user': '60/minute' #已登录用户每分钟可以请求60次
# },
'EXCEPTION_HANDLER': 'utils.exception.CustomExceptionHandler', # 自定义的异常处理
#线上部署正式环境关闭web接口测试页面
# 'DEFAULT_RENDERER_CLASSES':(
# 'rest_framework.renderers.JSONRenderer',
# ),
}
# ================================================= #
# ****************** simplejwt配置 ***************** #
# ================================================= #
from datetime import timedelta
SIMPLE_JWT = {
# token有效时长
'ACCESS_TOKEN_LIFETIME': timedelta(days=7),
# token刷新后的有效时间
'REFRESH_TOKEN_LIFETIME': timedelta(days=15),
# 设置header字段Authorization的值得前缀 JWT accesstoken字符串
'AUTH_HEADER_TYPES': ('JWT',),
'ROTATE_REFRESH_TOKENS': True
}
# ====================================#
# ****************swagger************#
#====================================#
SWAGGER_SETTINGS = {
# 基础样式
'SECURITY_DEFINITIONS': {
"basic":{#用户名密码cookie验证
'type': 'basic'
},
'JWT': {#通过jwt验证
'type': 'apiKey',
'name': 'Authorization',
'in': 'header'
},
# 'Query': {#通过query中auth变量验证
# 'type': 'apiKey',
# 'name': 'auth',
# 'in': 'query'
# }
},
# 如果需要登录才能够查看接口文档, 登录的链接使用restframework自带的.
'LOGIN_URL': 'rest_framework:login',
'LOGOUT_URL': 'rest_framework:logout',
# 'DOC_EXPANSION': None,
# 'SHOW_REQUEST_HEADERS':True,
# 'USE_SESSION_AUTH': True,
# 'DOC_EXPANSION': 'list',
# 接口文档中方法列表以首字母升序排列
'APIS_SORTER': 'alpha',
# 如果支持json提交, 则接口文档中包含json输入框
'JSON_EDITOR': True,
# 方法列表字母排序
'OPERATIONS_SORTER': 'alpha',
'VALIDATOR_URL': None,
'AUTO_SCHEMA_TYPE': 1, # 分组根据url层级分0、1 或 2 层
'DEFAULT_AUTO_SCHEMA_CLASS': 'utils.swagger.CustomSwaggerAutoSchema',
# 'DEFAULT_PARSER_CLASSES': (
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
# 'rest_framework.parsers.JSONParser',
# ),
}
# ================================================= #
# **************** 验证码配置 ******************* #
# ================================================= #
CAPTCHA_STATE = True
CAPTCHA_IMAGE_SIZE = (160, 60) # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4 # 字符个数
CAPTCHA_TIMEOUT = 1 # 超时(minutes)
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_FONT_SIZE = 42 # 字体大小
CAPTCHA_FOREGROUND_COLOR = '#296dff' # 前景色
CAPTCHA_BACKGROUND_COLOR = '#FFFFFF' # 背景色
CAPTCHA_NOISE_FUNCTIONS = (
'captcha.helpers.noise_arcs', # 线
# 'captcha.helpers.noise_dots', # 点
)
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #字母验证码
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge' # 加减乘除验证码
# ================================================= #
# ******************** celery配置 ******************** #
# ================================================= #
CELERY_TIMEZONE = 'Asia/Shanghai' # celery 时区问题
CELERY_BROKER_URL = f'{REDIS_URL}/10' # Broker配置使用Redis作为消息中间件(无密码)
#CELERY_BROKER_URL = 'redis://lybbn:{}@127.0.0.1:6379/10'.format('123456') #lybbn 代表 账号(没有可省略) {} 存放密码 127.0.0.1连接的 ip 6379端口 10 redis库
# CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/11' # 把任务结果存在了Redis
CELERY_RESULT_BACKEND = 'django-db' # celery结果存储到数据库中django-db
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' # Backend数据库
CELERY_RESULT_PERSISTENT = True
CELERY_RESULT_EXTENDED = True
DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_ENABLE_UTC = False
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600}# 连接超时
CELERY_TASK_SERIALIZER = 'json' # 任务序列化和反序列化使json
CELERY_RESULT_SERIALIZER = 'json'
#CELERYD_CONCURRENCY = 2 #并发worker数量
CELERY_WORKER_CONCURRENCY = 2 # 并发数
CELERYD_FORCE_EXECV = True #防止死锁,应确保为True
CELERY_TASK_TIME_LIMIT = 60*30*5 # 限制celery任务执行时间# 单个任务的运行时间限制,否则会被杀死
CELERYD_MAX_TASKS_PER_CHILD = 100 #worker执行100个任务自动销毁防止内存泄露
CELERYD_TASK_SOFT_TIME_LIMIT = 6000 #单个任务的运行时间不超过此值(秒),否则会抛出(SoftTimeLimitExceeded)异常停止任务
CELERY_DISABLE_RATE_LIMITS = True #即使任务设置了明确的速率限制,也禁用所有速率限制。
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True #去除celery6.0启动时warning警告确保在启动时进行代理连接重试
# ================================================= #
# ******************** 其他配置 ******************** #
# ================================================= #
# DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
API_LOG_ENABLE = True#全局控制日志记录
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
API_LOG_METHODS = ['POST', 'UPDATE', 'DELETE', 'PUT'] # ['POST', 'DELETE']
#日志记录显示的请求模块中文名映射
API_MODEL_MAP = {
"/token/": "登录模块",
"/api/token/": "登录模块",
"/api/super/operate/":"前端API关闭开启",
"/api/platformsettings/uploadplatformimg/":"图片上传",
}
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'