|
|
|
|
@ -0,0 +1,399 @@
|
|
|
|
|
"""
|
|
|
|
|
Django settings for djangoblog project.
|
|
|
|
|
项目配置文件:包含项目核心设置、数据库、中间件、静态资源等所有全局配置
|
|
|
|
|
Generated by 'django-admin startproject' using Django 1.10.2.
|
|
|
|
|
"""
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
# 导入Django国际化翻译工具
|
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def env_to_bool(env, default):
|
|
|
|
|
"""
|
|
|
|
|
环境变量转换工具函数:将环境变量的字符串值转为布尔值
|
|
|
|
|
- 若环境变量未设置,返回默认值
|
|
|
|
|
- 若环境变量存在,仅当值为'True'时返回True,其他情况返回False
|
|
|
|
|
"""
|
|
|
|
|
str_val = os.environ.get(env)
|
|
|
|
|
return default if str_val is None else str_val == 'True'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 基础路径配置 --------------------------
|
|
|
|
|
# 项目根目录:当前配置文件所在目录的父级目录(即项目根目录)
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 安全与调试配置 --------------------------
|
|
|
|
|
# 快速开发配置(生产环境需修改)
|
|
|
|
|
# SECURITY WARNING: 生产环境必须将SECRET_KEY通过环境变量配置,禁止硬编码
|
|
|
|
|
SECRET_KEY = os.environ.get(
|
|
|
|
|
'DJANGO_SECRET_KEY') or 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6'
|
|
|
|
|
|
|
|
|
|
# 调试模式:开发环境开启(True),生产环境必须关闭(False)
|
|
|
|
|
# 通过环境变量控制,默认开启调试
|
|
|
|
|
DEBUG = env_to_bool('DJANGO_DEBUG', True)
|
|
|
|
|
|
|
|
|
|
# 测试模式标识:当执行python manage.py test时,TESTING为True
|
|
|
|
|
TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'
|
|
|
|
|
|
|
|
|
|
# 允许访问的主机列表:生产环境需指定具体域名,禁止使用'*'(存在安全风险)
|
|
|
|
|
ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com']
|
|
|
|
|
|
|
|
|
|
# Django 4.0+新增:信任的CSRF源列表,防止跨站请求伪造,生产环境需配置真实域名
|
|
|
|
|
CSRF_TRUSTED_ORIGINS = ['http://example.com']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 应用配置 --------------------------
|
|
|
|
|
INSTALLED_APPS = [
|
|
|
|
|
# Django内置应用(精简版Admin,仅包含核心功能)
|
|
|
|
|
'django.contrib.admin.apps.SimpleAdminConfig',
|
|
|
|
|
'django.contrib.auth', # 用户认证系统
|
|
|
|
|
'django.contrib.contenttypes', # 内容类型框架(关联模型与数据表)
|
|
|
|
|
'django.contrib.sessions', # 会话管理
|
|
|
|
|
'django.contrib.messages', # 消息提示系统
|
|
|
|
|
'django.contrib.staticfiles', # 静态资源管理
|
|
|
|
|
'django.contrib.sites', # 多站点支持(用于sitemap等功能)
|
|
|
|
|
'django.contrib.sitemaps', # 站点地图生成
|
|
|
|
|
|
|
|
|
|
# 第三方应用
|
|
|
|
|
'mdeditor', # Markdown编辑器(用于文章编写)
|
|
|
|
|
'haystack', # 全文搜索框架
|
|
|
|
|
'compressor', # 静态资源压缩(CSS/JS合并压缩)
|
|
|
|
|
|
|
|
|
|
# 自定义应用
|
|
|
|
|
'blog', # 博客核心功能(文章、分类等)
|
|
|
|
|
'accounts', # 用户账户管理(自定义用户模型等)
|
|
|
|
|
'comments', # 评论功能
|
|
|
|
|
'oauth', # 第三方登录(如GitHub、微信等)
|
|
|
|
|
'servermanager',# 服务器管理(如系统监控等)
|
|
|
|
|
'owntracks', # 位置追踪(可选功能)
|
|
|
|
|
'djangoblog' # 项目主应用(全局配置、工具函数等)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 中间件配置 --------------------------
|
|
|
|
|
MIDDLEWARE = [
|
|
|
|
|
'django.middleware.security.SecurityMiddleware', # 安全相关中间件(防XSS、点击劫持等)
|
|
|
|
|
'django.contrib.sessions.middleware.SessionMiddleware', # 会话管理
|
|
|
|
|
'django.middleware.locale.LocaleMiddleware', # 国际化中间件(多语言支持)
|
|
|
|
|
'django.middleware.gzip.GZipMiddleware', # GZip压缩(减少响应体积)
|
|
|
|
|
# 'django.middleware.cache.UpdateCacheMiddleware', # 缓存更新(注释:当前未启用)
|
|
|
|
|
'django.middleware.common.CommonMiddleware', # 通用中间件(处理URL、反向解析等)
|
|
|
|
|
# 'django.middleware.cache.FetchFromCacheMiddleware', # 缓存读取(注释:当前未启用)
|
|
|
|
|
'django.middleware.csrf.CsrfViewMiddleware', # CSRF保护中间件
|
|
|
|
|
'django.contrib.auth.middleware.AuthenticationMiddleware', # 用户认证中间件
|
|
|
|
|
'django.contrib.messages.middleware.MessageMiddleware', # 消息提示中间件
|
|
|
|
|
'django.middleware.clickjacking.XFrameOptionsMiddleware', # 防点击劫持
|
|
|
|
|
'django.middleware.http.ConditionalGetMiddleware', # 处理HTTP条件请求(如304缓存)
|
|
|
|
|
'blog.middleware.OnlineMiddleware' # 自定义中间件(跟踪用户在线状态)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- URL与模板配置 --------------------------
|
|
|
|
|
# 项目主URL配置文件路径
|
|
|
|
|
ROOT_URLCONF = 'djangoblog.urls'
|
|
|
|
|
|
|
|
|
|
# 模板配置
|
|
|
|
|
TEMPLATES = [
|
|
|
|
|
{
|
|
|
|
|
'BACKEND': 'django.template.backends.django.DjangoTemplates', # Django模板引擎
|
|
|
|
|
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 全局模板目录(项目根目录下的templates)
|
|
|
|
|
'APP_DIRS': True, # 允许从各应用的templates目录加载模板
|
|
|
|
|
'OPTIONS': {
|
|
|
|
|
# 模板上下文处理器:向所有模板注入全局变量
|
|
|
|
|
'context_processors': [
|
|
|
|
|
'django.template.context_processors.debug', # 调试模式变量
|
|
|
|
|
'django.template.context_processors.request', # 请求对象(request)
|
|
|
|
|
'django.contrib.auth.context_processors.auth', # 用户认证变量(user)
|
|
|
|
|
'django.contrib.messages.context_processors.messages', # 消息提示变量
|
|
|
|
|
'blog.context_processors.seo_processor' # 自定义SEO处理器(注入SEO相关变量)
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# WSGI应用入口(用于部署,如Gunicorn、uWSGI)
|
|
|
|
|
WSGI_APPLICATION = 'djangoblog.wsgi.application'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 数据库配置 --------------------------
|
|
|
|
|
DATABASES = {
|
|
|
|
|
'default': {
|
|
|
|
|
'ENGINE': 'django.db.backends.mysql', # 数据库引擎(MySQL)
|
|
|
|
|
'NAME': os.environ.get('DJANGO_MYSQL_DATABASE') or 'djangoblog', # 数据库名
|
|
|
|
|
'USER': os.environ.get('DJANGO_MYSQL_USER') or 'root', # 数据库用户名
|
|
|
|
|
'PASSWORD': os.environ.get('DJANGO_MYSQL_PASSWORD') or 'LY181828', # 数据库密码
|
|
|
|
|
'HOST': os.environ.get('DJANGO_MYSQL_HOST') or '127.0.0.1', # 数据库主机
|
|
|
|
|
'PORT': int(os.environ.get('DJANGO_MYSQL_PORT') or 3306), # 数据库端口
|
|
|
|
|
'OPTIONS': {'charset': 'utf8mb4'}, # 数据库字符集(支持emoji表情)
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 密码验证配置 --------------------------
|
|
|
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
|
|
|
# 验证密码与用户名/邮箱是否相似
|
|
|
|
|
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
|
|
|
|
|
# 验证密码最小长度(默认8位)
|
|
|
|
|
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
|
|
|
|
|
# 验证密码是否为常见弱密码(如123456)
|
|
|
|
|
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
|
|
|
|
|
# 验证密码是否全为数字
|
|
|
|
|
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 国际化与时间配置 --------------------------
|
|
|
|
|
# 支持的语言列表(英文、简体中文、繁体中文)
|
|
|
|
|
LANGUAGES = (
|
|
|
|
|
('en', _('English')),
|
|
|
|
|
('zh-hans', _('Simplified Chinese')),
|
|
|
|
|
('zh-hant', _('Traditional Chinese')),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# 语言文件目录(存放翻译文件的路径)
|
|
|
|
|
LOCALE_PATHS = (os.path.join(BASE_DIR, 'locale'),)
|
|
|
|
|
|
|
|
|
|
# 默认语言(简体中文)
|
|
|
|
|
LANGUAGE_CODE = 'zh-hans'
|
|
|
|
|
|
|
|
|
|
# 时区(上海时区,与UTC时差+8)
|
|
|
|
|
TIME_ZONE = 'Asia/Shanghai'
|
|
|
|
|
|
|
|
|
|
# 启用国际化
|
|
|
|
|
USE_I18N = True
|
|
|
|
|
|
|
|
|
|
# 启用本地化(日期、时间格式等)
|
|
|
|
|
USE_L10N = True
|
|
|
|
|
|
|
|
|
|
# 禁用UTC时间(使用本地时间存储数据库时间)
|
|
|
|
|
USE_TZ = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 全文搜索配置(Haystack) --------------------------
|
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
|
|
|
'default': {
|
|
|
|
|
# 搜索引擎:自定义中文Whoosh引擎(支持中文分词)
|
|
|
|
|
'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine',
|
|
|
|
|
# 搜索索引存储路径(项目配置文件目录下的whoosh_index)
|
|
|
|
|
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 实时更新搜索索引:当文章新增/修改/删除时,自动更新搜索索引
|
|
|
|
|
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 用户认证配置 --------------------------
|
|
|
|
|
# 自定义认证后端:允许用户用用户名或邮箱登录
|
|
|
|
|
AUTHENTICATION_BACKENDS = ['accounts.user_login_backend.EmailOrUsernameModelBackend']
|
|
|
|
|
|
|
|
|
|
# 自定义用户模型:替换Django内置的User模型(关联accounts应用的BlogUser)
|
|
|
|
|
AUTH_USER_MODEL = 'accounts.BlogUser'
|
|
|
|
|
|
|
|
|
|
# 登录页面URL:未登录用户访问需认证页面时,重定向到该URL
|
|
|
|
|
LOGIN_URL = '/login/'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 静态资源与媒体文件配置 --------------------------
|
|
|
|
|
# 静态资源收集目录(生产环境使用python manage.py collectstatic收集后的路径)
|
|
|
|
|
STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
|
|
|
|
|
|
|
|
|
|
# 静态资源URL前缀(前端访问静态资源的路径,如http://example.com/static/)
|
|
|
|
|
STATIC_URL = '/static/'
|
|
|
|
|
|
|
|
|
|
# 全局静态资源目录(项目根目录下的static文件夹)
|
|
|
|
|
STATICFILES = os.path.join(BASE_DIR, 'static')
|
|
|
|
|
|
|
|
|
|
# 媒体文件(用户上传文件,如文章图片)存储目录
|
|
|
|
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
|
|
|
|
|
|
|
|
|
|
# 媒体文件URL前缀(前端访问上传文件的路径,如http://example.com/media/)
|
|
|
|
|
MEDIA_URL = '/media/'
|
|
|
|
|
|
|
|
|
|
# 静态资源查找器(指定Django如何查找静态文件)
|
|
|
|
|
STATICFILES_FINDERS = (
|
|
|
|
|
'django.contrib.staticfiles.finders.FileSystemFinder', # 从全局STATICFILES目录查找
|
|
|
|
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 从各应用的static目录查找
|
|
|
|
|
'compressor.finders.CompressorFinder', # 从compressor压缩后的目录查找
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 静态资源压缩配置(Compressor) --------------------------
|
|
|
|
|
# 启用压缩(生产环境建议开启,开发环境可关闭)
|
|
|
|
|
COMPRESS_ENABLED = True
|
|
|
|
|
# COMPRESS_OFFLINE = True # 离线压缩(注释:当前未启用,适合生产环境)
|
|
|
|
|
|
|
|
|
|
# CSS压缩过滤器:1. 转换相对URL为绝对URL;2. 压缩CSS代码
|
|
|
|
|
COMPRESS_CSS_FILTERS = [
|
|
|
|
|
'compressor.filters.css_default.CssAbsoluteFilter',
|
|
|
|
|
'compressor.filters.cssmin.CSSMinFilter'
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# JS压缩过滤器:压缩JS代码
|
|
|
|
|
COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 缓存配置 --------------------------
|
|
|
|
|
# HTTP缓存超时时间(单位:秒,2592000秒=30天)
|
|
|
|
|
CACHE_CONTROL_MAX_AGE = 2592000
|
|
|
|
|
|
|
|
|
|
# 默认缓存:本地内存缓存(适合开发环境,生产环境建议用Redis/Memcached)
|
|
|
|
|
CACHES = {
|
|
|
|
|
'default': {
|
|
|
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
|
|
|
'TIMEOUT': 10800, # 缓存超时时间(3小时)
|
|
|
|
|
'LOCATION': 'unique-snowflake', # 缓存实例标识(唯一即可)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# 若环境变量配置了Redis地址,则使用Redis作为缓存(生产环境推荐)
|
|
|
|
|
if os.environ.get("DJANGO_REDIS_URL"):
|
|
|
|
|
CACHES = {
|
|
|
|
|
'default': {
|
|
|
|
|
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
|
|
|
|
|
'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 其他业务配置 --------------------------
|
|
|
|
|
# 多站点支持的站点ID(默认1,与django.contrib.sites配合使用)
|
|
|
|
|
SITE_ID = 1
|
|
|
|
|
|
|
|
|
|
# 百度链接提交URL:用于向百度搜索引擎提交新链接(SEO优化)
|
|
|
|
|
BAIDU_NOTIFY_URL = os.environ.get('DJANGO_BAIDU_NOTIFY_URL') or \
|
|
|
|
|
'http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn'
|
|
|
|
|
|
|
|
|
|
# 时间格式:全局日期时间显示格式
|
|
|
|
|
TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
|
|
|
|
DATE_TIME_FORMAT = '%Y-%m-%d'
|
|
|
|
|
|
|
|
|
|
# Bootstrap颜色样式列表(用于文章标签、按钮等UI组件)
|
|
|
|
|
BOOTSTRAP_COLOR_TYPES = ['default', 'primary', 'success', 'info', 'warning', 'danger']
|
|
|
|
|
|
|
|
|
|
# 分页配置:每页显示的文章数量
|
|
|
|
|
PAGINATE_BY = 10
|
|
|
|
|
|
|
|
|
|
# X-Frame-Options配置:仅允许同域嵌入iframe(防点击劫持)
|
|
|
|
|
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
|
|
|
|
|
|
|
|
|
# 默认自增字段类型(Django 3.2+新增,避免主键溢出)
|
|
|
|
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|
|
|
|
|
|
|
|
|
# 微信管理员密码(两次MD5加密,用于微信后台管理验证)
|
|
|
|
|
WXADMIN = os.environ.get('DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- Elasticsearch配置(可选) --------------------------
|
|
|
|
|
# 若环境变量配置了Elasticsearch地址,则使用Elasticsearch作为搜索引擎(替代Whoosh)
|
|
|
|
|
if os.environ.get('DJANGO_ELASTICSEARCH_HOST'):
|
|
|
|
|
ELASTICSEARCH_DSL = {
|
|
|
|
|
'default': {'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST')},
|
|
|
|
|
}
|
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
|
|
|
'default': {'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine'},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 日志配置 --------------------------
|
|
|
|
|
# 日志存储目录(项目根目录下的logs文件夹)
|
|
|
|
|
LOG_PATH = os.path.join(BASE_DIR, 'logs')
|
|
|
|
|
# 若目录不存在则创建(exist_ok=True避免重复创建报错)
|
|
|
|
|
if not os.path.exists(LOG_PATH):
|
|
|
|
|
os.makedirs(LOG_PATH, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
LOGGING = {
|
|
|
|
|
'version': 1, # 日志配置版本(固定为1)
|
|
|
|
|
'disable_existing_loggers': False, # 不禁用已存在的日志器
|
|
|
|
|
'root': { # 根日志器(所有未指定日志器的日志都会走这里)
|
|
|
|
|
'level': 'INFO', # 日志级别(INFO及以上会被记录)
|
|
|
|
|
'handlers': ['console', 'log_file'], # 日志处理器(控制台+文件)
|
|
|
|
|
},
|
|
|
|
|
'formatters': { # 日志格式
|
|
|
|
|
'verbose': { # 详细格式(包含时间、级别、模块、行号等)
|
|
|
|
|
'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d %(module)s] %(message)s',
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'filters': { # 日志过滤器
|
|
|
|
|
'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}, # 仅DEBUG=False时生效
|
|
|
|
|
'require_debug_true': {'()': 'django.utils.log.RequireDebugTrue'}, # 仅DEBUG=True时生效
|
|
|
|
|
},
|
|
|
|
|
'handlers': { # 日志处理器(定义日志如何输出)
|
|
|
|
|
'log_file': { # 文件处理器(按天分割日志)
|
|
|
|
|
'level': 'INFO',
|
|
|
|
|
'class': 'logging.handlers.TimedRotatingFileHandler', # 按时间轮转的文件处理器
|
|
|
|
|
'filename': os.path.join(LOG_PATH, 'djangoblog.log'), # 日志文件路径
|
|
|
|
|
'when': 'D', # 轮转周期(每天一个文件)
|
|
|
|
|
'formatter': 'verbose', # 使用详细格式
|
|
|
|
|
'interval': 1, # 轮转间隔(1天)
|
|
|
|
|
'delay': True, # 延迟创建文件(直到有日志时才创建)
|
|
|
|
|
'backupCount': 5, # 保留5个备份日志文件
|
|
|
|
|
'encoding': 'utf-8' # 日志文件编码
|
|
|
|
|
},
|
|
|
|
|
'console': { # 控制台处理器(仅开发环境显示)
|
|
|
|
|
'level': 'DEBUG',
|
|
|
|
|
'filters': ['require_debug_true'], # 仅DEBUG=True时生效
|
|
|
|
|
'class': 'logging.StreamHandler', # 输出到控制台
|
|
|
|
|
'formatter': 'verbose'
|
|
|
|
|
},
|
|
|
|
|
'null': {'class': 'logging.NullHandler'}, # 空处理器(丢弃日志)
|
|
|
|
|
'mail_admins': { # 邮件处理器(发生ERROR时通知管理员)
|
|
|
|
|
'level': 'ERROR',
|
|
|
|
|
'filters': ['require_debug_false'], # 仅生产环境(DEBUG=False)生效
|
|
|
|
|
'class': 'django.utils.log.AdminEmailHandler' # 发送邮件给ADMINS列表
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'loggers': { # 自定义日志器(针对特定模块)
|
|
|
|
|
'djangoblog': { # 项目主模块日志
|
|
|
|
|
'handlers': ['log_file', 'console'],
|
|
|
|
|
'level': 'INFO',
|
|
|
|
|
'propagate': True, # 是否向上传递日志(到root日志器)
|
|
|
|
|
},
|
|
|
|
|
'django.request': { # Django请求相关日志(如404、500错误)
|
|
|
|
|
'handlers': ['mail_admins'],
|
|
|
|
|
'level': 'ERROR',
|
|
|
|
|
'propagate': False, # 不向上传递(避免重复记录)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 邮件配置 --------------------------
|
|
|
|
|
# 邮件后端(SMTP服务)
|
|
|
|
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
|
|
|
# 是否使用TLS加密(与SSL二选一,根据邮件服务商配置)
|
|
|
|
|
EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False)
|
|
|
|
|
# 是否使用SSL加密(阿里云邮箱等常用465端口+SSL)
|
|
|
|
|
EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True)
|
|
|
|
|
# 邮件服务器地址(如阿里云邮箱为smtp.mxhichina.com)
|
|
|
|
|
EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST') or 'smtp.mxhichina.com'
|
|
|
|
|
# 邮件服务器端口(SSL通常为465,TLS通常为587)
|
|
|
|
|
EMAIL_PORT = int(os.environ.get('DJANGO_EMAIL_PORT') or 465)
|
|
|
|
|
# 发送邮件的用户名(邮箱地址)
|
|
|
|
|
EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER')
|
|
|
|
|
# 发送邮件的密码(邮箱授权码,非登录密码)
|
|
|
|
|
EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD')
|
|
|
|
|
# 默认发件人(与EMAIL_HOST_USER一致)
|
|
|
|
|
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
|
|
|
|
# 管理员邮件(与ADMINS配合使用)
|
|
|
|
|
SERVER_EMAIL = EMAIL_HOST_USER
|
|
|
|
|
|
|
|
|
|
# 管理员列表:发生ERROR时会收到邮件通知
|
|
|
|
|
ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# -------------------------- 插件系统配置 --------------------------
|
|
|
|
|
# 插件目录(项目根目录下的plugins文件夹)
|
|
|
|
|
PLUGINS_DIR = BASE_DIR / 'plugins'
|
|
|
|
|
|
|
|
|
|
# 激活的插件列表(按需启用,提供额外功能)
|
|
|
|
|
ACTIVE_PLUGINS = [
|
|
|
|
|
'article_copyright', # 文章版权声明
|
|
|
|
|
'reading_time', # 文章阅读时长估算
|
|
|
|
|
'external_links', # 外部链接处理(如添加nofollow)
|
|
|
|
|
'view_count', # 文章阅读量统计
|
|
|
|
|
'seo_optimize' # SEO优化(如自动生成meta标签)
|
|
|
|
|
]
|