Files
server/server/settings.py
T

416 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 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"