416 lines
14 KiB
Python
416 lines
14 KiB
Python
"""
|
||
Django settings for server 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/
|
||
"""
|
||
import os
|
||
from pathlib import Path
|
||
|
||
import environ
|
||
from loguru import logger
|
||
|
||
env = environ.Env()
|
||
|
||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||
|
||
# 获取 env文件路径
|
||
env_file = BASE_DIR / "db/.env"
|
||
|
||
environ.Env.read_env(env_file)
|
||
logger.info(".ENV变量输出", env.ENVIRON)
|
||
# 日志文件存储配置
|
||
LOGURU_FILE = {
|
||
"is_show": "off",
|
||
"level": "ERROR",
|
||
'path': os.path.join(Path(__file__).parent, 'db/logs', 'test{time:YYYY-MM-DD}.logu'),
|
||
"rotation": "10MB",
|
||
'retention': "7days",
|
||
}
|
||
|
||
# 日志控制台配置
|
||
LOGURU_CONSOLE = {
|
||
"is_show": "on", # 配置是否开启控制台打印日志
|
||
"level": "INFO", # 最低打印级别是info级别
|
||
}
|
||
|
||
# 日志文件夹不存在时创建
|
||
logs_path = os.path.join(BASE_DIR, 'db/logs')
|
||
if not os.path.exists(logs_path):
|
||
os.makedirs(logs_path)
|
||
|
||
# Quick-start development settings - unsuitable for production
|
||
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/
|
||
|
||
# SECURITY WARNING: keep the secret key used in production secret!
|
||
SECRET_KEY = 'django-insecure-gr&k$v)_t*ax)yr1v9iz3x%$-j812ajpxs+fe2dn*dgy=a!730'
|
||
|
||
# SECURITY WARNING: don't run with debug turned on in production!
|
||
DEBUG = True
|
||
|
||
ALLOWED_HOSTS = ['*', "127.0.0.1", "localhost"]
|
||
|
||
# 2. 【必须添加】这个配置专门用于解决 Origin checking failed 报错
|
||
# 注意:必须包含协议头 (http://) 和端口号
|
||
CSRF_TRUSTED_ORIGINS = [
|
||
'http://127.0.0.1:11111', # 对应你报错的端口
|
||
'http://127.0.0.1',
|
||
'http://localhost:11111',
|
||
'http://localhost',
|
||
]
|
||
|
||
AUTH_USER_MODEL = 'users.User'
|
||
|
||
# Application definition
|
||
|
||
INSTALLED_APPS = [
|
||
'simpleui',
|
||
'django.contrib.admin',
|
||
'django.contrib.auth',
|
||
'django.contrib.contenttypes',
|
||
'django.contrib.sessions',
|
||
'django.contrib.messages',
|
||
'django.contrib.staticfiles',
|
||
'ninja_extra',
|
||
'import_export',
|
||
'django_ckeditor_5',
|
||
'base.apps.BaseConfig',
|
||
'article.apps.ArticleConfig',
|
||
'users.apps.UsersConfig',
|
||
'front.apps.ContentConfig',
|
||
'news.apps.NewsConfig',
|
||
'django_seed',
|
||
]
|
||
|
||
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 = 'server.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',
|
||
'base.context_processors.site_info',
|
||
],
|
||
},
|
||
},
|
||
]
|
||
|
||
WSGI_APPLICATION = 'server.wsgi.application'
|
||
ASGI_APPLICATION = 'server.asgi.application'
|
||
|
||
# Database
|
||
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases
|
||
|
||
if env('DB_REMOTE', default=False):
|
||
# mysql_connect = dj_database_url.parse(os.getenv('MYSQL_CONNECTION'), conn_max_age=0)
|
||
# print("数据库连接信息", mysql_connect)
|
||
DATABASES = {
|
||
'default': {
|
||
'ENGINE': env('DB_ENGINE', default='dj_db_conn_pool.backends.postgresql'),
|
||
'NAME': env('DB_NAME', default='harvest'),
|
||
'USER': env('DB_USER', default='harvest'),
|
||
'PASSWORD': env('DB_PASSWORD', default='harvest'),
|
||
'HOST': env('DB_HOST', default='harvest_postgres'),
|
||
'PORT': env('DB_PORT', default=5432),
|
||
'CONN_MAX_AGE': env('DB_CONN_MAX_AGE', default=0), # 必须设为 0,让池管理连接生命周期
|
||
'OPTIONS': {
|
||
# 'MAX_CONNS': env('DB_MAX_CONNS', default=30), # 池中最大物理连接数 (根据 PG 总限制调整)
|
||
# 'REUSE_CONNS': env('DB_REUSE_CONNS', default=10), # 最小保留连接数
|
||
},
|
||
'POOL_OPTIONS': {
|
||
'POOL_SIZE': env('DB_MAX_CONNS', default=100), # 增加连接池大小
|
||
'MAX_OVERFLOW': 20, # 增加最大溢出连接数
|
||
'TIMEOUT': 30, # 连接超时设置
|
||
}
|
||
},
|
||
}
|
||
else:
|
||
DATABASES = {
|
||
'default': {
|
||
'ENGINE': 'django.db.backends.sqlite3',
|
||
'NAME': BASE_DIR / 'db/data.sqlite3',
|
||
'OPTIONS': {
|
||
'timeout': 120,
|
||
'check_same_thread': False
|
||
}
|
||
},
|
||
}
|
||
|
||
CACHES = {
|
||
'default': {
|
||
# 指定使用本地内存缓存后端
|
||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||
|
||
# 缓存实例的名称,用于区分不同的内存存储
|
||
# 如果只有一个 locmem 缓存,可以忽略此项,但建议设置
|
||
'LOCATION': 'unique-snowflake',
|
||
|
||
# (可选) 默认超时时间,单位:秒
|
||
'TIMEOUT': 300,
|
||
|
||
# (可选) 最大缓存条目数,超过后会根据 LRU 策略淘汰旧数据
|
||
'OPTIONS': {
|
||
'MAX_ENTRIES': 1000,
|
||
'CULL_FREQUENCY': 3, # 到达 MAX_ENTRIES 时,剔除 1/CULL_FREQUENCY 的数据
|
||
}
|
||
}
|
||
}
|
||
# 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 = "zh-Hans"
|
||
|
||
TIME_ZONE = "Asia/Shanghai"
|
||
|
||
USE_I18N = True
|
||
|
||
USE_TZ = True
|
||
|
||
# Static files (CSS, JavaScript, Images)
|
||
# https://docs.djangoproject.com/en/6.0/howto/static-files/
|
||
|
||
STATIC_URL = 'static/'
|
||
# STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||
|
||
STATICFILES_DIRS = (
|
||
os.path.join(os.path.join(BASE_DIR, 'static')),
|
||
)
|
||
|
||
MEDIA_URL = '/media/'
|
||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||
|
||
# 日志配置
|
||
LOGGING = {
|
||
'version': 1, # 版本
|
||
'disable_existing_loggers': False, # 是否禁用已经存在的日志器
|
||
'formatters': { # 日志信息显示的格式
|
||
'verbose': {
|
||
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
|
||
},
|
||
'simple': {
|
||
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
|
||
},
|
||
},
|
||
'filters': { # 过滤器
|
||
'require_debug_true': { # django在debug模式下才输出日志
|
||
'()': 'django.utils.log.RequireDebugTrue',
|
||
},
|
||
},
|
||
'handlers': { # 日志处理方法
|
||
'console': { # 向终端中输出日志
|
||
'level': 'DEBUG', # 输出等级为“INFO”
|
||
'filters': ['require_debug_true'],
|
||
'class': 'logging.StreamHandler',
|
||
'formatter': 'simple'
|
||
},
|
||
'file': { # 向文件中输出日志
|
||
'level': os.getenv('LOGGER_LEVEL') if os.getenv('LOGGER_LEVEL') else 'INFO', # 输出等级为“INFO”
|
||
# 新增内容
|
||
# 'class': 'logging.handlers.TimedRotatingFileHandler',
|
||
# 'filename': os.path.join(BASE_DIR, 'logs/logs.log'),
|
||
# 'when': 'm',
|
||
# 'interval': 10,
|
||
# 'backupCount': 10,
|
||
'class': 'logging.handlers.RotatingFileHandler',
|
||
'filename': BASE_DIR / "db/logs/django_server.log", # 日志文件的位置
|
||
'maxBytes': 5 * 1024 * 1024, # 日志文件的大小(300*1024*1024为300MB)
|
||
'backupCount': 10, # 日志文件的数量(超过设定的最大值会自动备份,备份数量最大值为10)
|
||
'formatter': 'verbose', # 日志输出格式:使用了在之前定义的'verbose'
|
||
'encoding': 'utf-8' # 新增此行,指定文件编码为UTF-8
|
||
},
|
||
},
|
||
'loggers': { # 日志器
|
||
'ptools': { # 定义了一个名为django的日志器
|
||
'handlers': ['console', 'file'], # 可以同时向终端与文件中输出日志
|
||
'propagate': True, # 是否继续传递日志信息
|
||
'level': os.getenv('LOGGER_LEVEL') if os.getenv('LOGGER_LEVEL') else 'INFO', # 日志器接收的最低日志级别
|
||
},
|
||
'requests': {
|
||
'level': 'WARNING',
|
||
'handlers': ['console'], # 或你定义的其他 handler
|
||
'propagate': False,
|
||
},
|
||
'urllib3': {
|
||
'level': 'WARNING',
|
||
'handlers': ['console'],
|
||
'propagate': False,
|
||
},
|
||
}
|
||
}
|
||
# 调整POST传输数据文件大小限制
|
||
DATA_UPLOAD_MAX_MEMORY_SIZE = 25 * 1024 * 1024 * 1024
|
||
FILE_UPLOAD_MAX_MEMORY_SIZE = 25 * 1024 * 1024 * 1024
|
||
|
||
# 自定义UI配置
|
||
SIMPLEUI_HOME_TITLE = '长白山消防支队'
|
||
SIMPLEUI_HOME_ICON = 'fa fa-optin-monster'
|
||
SIMPLEUI_LOGO = 'https://avatars2.githubusercontent.com/u/13655483?s=60&v=4'
|
||
SIMPLEUI_HOME_INFO = False
|
||
SIMPLEUI_INDEX = ''
|
||
SIMPLEUI_ANALYSIS = False
|
||
SIMPLEUI_STATIC_OFFLINE = True
|
||
SIMPLEUI_HOME_ACTION = False
|
||
|
||
CKEDITOR_CONFIGS = {
|
||
'default': {
|
||
'toolbar': 'full',
|
||
'height': 300,
|
||
'width': '100%',
|
||
},
|
||
}
|
||
|
||
customColorPalette = [
|
||
{
|
||
'color': 'hsl(4, 90%, 58%)',
|
||
'label': 'Red'
|
||
},
|
||
{
|
||
'color': 'hsl(340, 82%, 52%)',
|
||
'label': 'Pink'
|
||
},
|
||
{
|
||
'color': 'hsl(291, 64%, 42%)',
|
||
'label': 'Purple'
|
||
},
|
||
{
|
||
'color': 'hsl(262, 52%, 47%)',
|
||
'label': 'Deep Purple'
|
||
},
|
||
{
|
||
'color': 'hsl(231, 48%, 48%)',
|
||
'label': 'Indigo'
|
||
},
|
||
{
|
||
'color': 'hsl(207, 90%, 54%)',
|
||
'label': 'Blue'
|
||
},
|
||
]
|
||
|
||
# CKEDITOR_5_CUSTOM_CSS = 'path_to.css' # optional
|
||
CKEDITOR_5_ALLOW_ALL_FILE_TYPES = True
|
||
CKEDITOR_5_UPLOAD_FILE_TYPES = [
|
||
'jpeg', 'png', 'jpg', 'gif', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
|
||
]
|
||
# 允许上传非图片文件(PDF、Word、Excel、ZIP等)
|
||
CKEDITOR_ALLOW_NONIMAGE_FILES = True # 必须设为 True
|
||
CKEDITOR_5_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage' # optional
|
||
CKEDITOR_5_CONFIGS = {
|
||
'default': {
|
||
'toolbar': {
|
||
'items': ['heading', '|', 'bold', 'italic', 'link',
|
||
'bulletedList', 'numberedList', 'blockQuote', 'imageUpload', 'uploadFile', ],
|
||
},
|
||
'language': 'zh-cn',
|
||
# 2. 允许上传的文件类型 (根据需要扩展)
|
||
'fileUploader': {
|
||
'supportedFileTypes': ['pdf', 'doc', 'docx', 'zip', 'txt', 'jpg', 'png'],
|
||
}
|
||
},
|
||
'extends': {
|
||
'blockToolbar': [
|
||
'paragraph', 'heading1', 'heading2', 'heading3',
|
||
'|',
|
||
'bulletedList', 'numberedList',
|
||
'|',
|
||
'blockQuote',
|
||
],
|
||
'toolbar': {
|
||
'items': ['heading', '|', 'outdent', 'indent', '|', 'bold', 'italic', 'link', 'underline', 'strikethrough',
|
||
'code', 'subscript', 'superscript', 'highlight', '|', 'codeBlock', 'sourceEditing', 'insertImage',
|
||
'bulletedList', 'numberedList', 'todoList', '|', 'blockQuote', 'imageUpload', 'uploadFile', '|',
|
||
'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor', 'mediaEmbed', 'removeFormat',
|
||
'insertTable',
|
||
],
|
||
'shouldNotGroupWhenFull': 'true'
|
||
},
|
||
# --- 在 extends 配置中也必须加上这个 ---
|
||
'fileUploader': {
|
||
'supportedFileTypes': ['pdf', 'doc', 'docx', 'zip', 'txt']
|
||
},
|
||
'image': {
|
||
'toolbar': ['imageTextAlternative', '|', 'imageStyle:alignLeft',
|
||
'imageStyle:alignRight', 'imageStyle:alignCenter', 'imageStyle:side', '|'],
|
||
'styles': [
|
||
'full',
|
||
'side',
|
||
'alignLeft',
|
||
'alignRight',
|
||
'alignCenter',
|
||
]
|
||
|
||
},
|
||
'table': {
|
||
'contentToolbar': ['tableColumn', 'tableRow', 'mergeTableCells',
|
||
'tableProperties', 'tableCellProperties'],
|
||
'tableProperties': {
|
||
'borderColors': customColorPalette,
|
||
'backgroundColors': customColorPalette
|
||
},
|
||
'tableCellProperties': {
|
||
'borderColors': customColorPalette,
|
||
'backgroundColors': customColorPalette
|
||
}
|
||
},
|
||
'heading': {
|
||
'options': [
|
||
{'model': 'paragraph', 'title': 'Paragraph', 'class': 'ck-heading_paragraph'},
|
||
{'model': 'heading1', 'view': 'h1', 'title': 'Heading 1', 'class': 'ck-heading_heading1'},
|
||
{'model': 'heading2', 'view': 'h2', 'title': 'Heading 2', 'class': 'ck-heading_heading2'},
|
||
{'model': 'heading3', 'view': 'h3', 'title': 'Heading 3', 'class': 'ck-heading_heading3'}
|
||
]
|
||
}
|
||
},
|
||
'list': {
|
||
'properties': {
|
||
'styles': 'true',
|
||
'startIndex': 'true',
|
||
'reversed': 'true',
|
||
}
|
||
}
|
||
}
|
||
|
||
# Define a constant in settings.py to specify file upload permissions
|
||
CKEDITOR_5_FILE_UPLOAD_PERMISSION = "staff" # Possible values: "staff", "authenticated", "any"
|
||
|
||
# CK_EDITOR_5_UPLOAD_FILE_VIEW_NAME = "custom_upload_file"
|