|
|
|
|
@ -13,371 +13,331 @@ import os
|
|
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
# 导入 Django 国际化工具:用于多语言文本翻译
|
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 自定义工具函数:将环境变量转为布尔值(处理配置的灵活性)
|
|
|
|
|
def env_to_bool(env, default):
|
|
|
|
|
str_val = os.environ.get(env) # 从环境变量获取值
|
|
|
|
|
# 若环境变量未设置则返回默认值,否则判断字符串是否为'True'
|
|
|
|
|
str_val = os.environ.get(env)
|
|
|
|
|
return default if str_val is None else str_val == 'True'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 项目根目录:定位到 settings.py 所在目录的父目录(项目根路径)
|
|
|
|
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
|
|
|
|
# Quick-start development settings - unsuitable for production
|
|
|
|
|
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
|
|
|
|
|
|
|
|
|
# 安全密钥:用于加密会话、CSRF 令牌等敏感数据(生产环境需通过环境变量设置,避免硬编码)
|
|
|
|
|
# SECURITY WARNING: keep the secret key used in production secret!
|
|
|
|
|
SECRET_KEY = os.environ.get(
|
|
|
|
|
'DJANGO_SECRET_KEY') or 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6'
|
|
|
|
|
# 调试模式:开发环境开启(便于调试),生产环境必须关闭(避免暴露敏感信息)
|
|
|
|
|
# SECURITY WARNING: don't run with debug turned on in production!
|
|
|
|
|
DEBUG = env_to_bool('DJANGO_DEBUG', True)
|
|
|
|
|
# DEBUG = False # 生产环境手动关闭调试的示例
|
|
|
|
|
# 测试模式标识:判断是否正在执行测试命令(如 python manage.py test)
|
|
|
|
|
# DEBUG = False
|
|
|
|
|
TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'
|
|
|
|
|
|
|
|
|
|
# 允许访问的主机:生产环境需指定具体域名,开发环境用'*'允许所有主机(存在安全风险,生产禁用)
|
|
|
|
|
# ALLOWED_HOSTS = [] # 生产环境初始空配置(需补充具体域名)
|
|
|
|
|
# ALLOWED_HOSTS = []
|
|
|
|
|
ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com']
|
|
|
|
|
# Django 4.0+ 新增配置:信任的 CSRF 来源(避免跨域 CSRF 验证失败,生产环境需指定真实域名)
|
|
|
|
|
# django 4.0新增配置
|
|
|
|
|
CSRF_TRUSTED_ORIGINS = ['http://example.com']
|
|
|
|
|
# Application definition
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Application definition(已安装的应用:Django 内置应用 + 第三方应用 + 自定义应用)
|
|
|
|
|
INSTALLED_APPS = [
|
|
|
|
|
# Django 内置 Admin 应用:使用精简版配置(SimpleAdminConfig),减少不必要功能
|
|
|
|
|
# 'django.contrib.admin', # 完整版 Admin 配置(此处注释,使用精简版)
|
|
|
|
|
# 'django.contrib.admin',
|
|
|
|
|
'django.contrib.admin.apps.SimpleAdminConfig',
|
|
|
|
|
'django.contrib.auth', # 认证与授权系统
|
|
|
|
|
'django.contrib.contenttypes', # 内容类型框架(关联模型与权限)
|
|
|
|
|
'django.contrib.sessions', # 会话管理(用户登录状态保持)
|
|
|
|
|
'django.contrib.messages', # 消息提示系统(如登录成功提示)
|
|
|
|
|
'django.contrib.staticfiles', # 静态文件管理(CSS/JS/图片)
|
|
|
|
|
'django.contrib.sites', # 多站点支持(用于 RSS、OAuth 等功能)
|
|
|
|
|
'django.contrib.sitemaps', # 站点地图生成(利于 SEO)
|
|
|
|
|
'mdeditor', # 第三方应用:Markdown 编辑器(用于文章编写)
|
|
|
|
|
'haystack', # 第三方应用:搜索框架(对接 Whoosh/Elasticsearch)
|
|
|
|
|
'blog', # 自定义应用:博客核心功能(文章、分类等)
|
|
|
|
|
'accounts', # 自定义应用:用户账户管理(登录、注册等)
|
|
|
|
|
'comments', # 自定义应用:评论功能
|
|
|
|
|
'oauth', # 自定义应用:第三方登录(如 GitHub、微博)
|
|
|
|
|
'servermanager', # 自定义应用:服务器管理(命令执行、日志记录)
|
|
|
|
|
'owntracks', # 自定义应用:位置追踪(OwnTracks 数据管理)
|
|
|
|
|
'compressor', # 第三方应用:静态文件压缩(CSS/JS 压缩,提升加载速度)
|
|
|
|
|
'djangoblog' # 自定义应用:项目核心配置(如信号、插件)
|
|
|
|
|
'django.contrib.auth',
|
|
|
|
|
'django.contrib.contenttypes',
|
|
|
|
|
'django.contrib.sessions',
|
|
|
|
|
'django.contrib.messages',
|
|
|
|
|
'django.contrib.staticfiles',
|
|
|
|
|
'django.contrib.sites',
|
|
|
|
|
'django.contrib.sitemaps',
|
|
|
|
|
'mdeditor',
|
|
|
|
|
'haystack',
|
|
|
|
|
'blog',
|
|
|
|
|
'accounts',
|
|
|
|
|
'comments',
|
|
|
|
|
'oauth',
|
|
|
|
|
'servermanager',
|
|
|
|
|
'owntracks',
|
|
|
|
|
'compressor',
|
|
|
|
|
'djangoblog'
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# 中间件:处理请求/响应的钩子(按顺序执行,影响请求流程)
|
|
|
|
|
MIDDLEWARE = [
|
|
|
|
|
'django.middleware.security.SecurityMiddleware', # 安全相关中间件(HTTPS、XSS 防护等)
|
|
|
|
|
'django.contrib.sessions.middleware.SessionMiddleware', # 会话管理中间件
|
|
|
|
|
'django.middleware.locale.LocaleMiddleware', # 国际化中间件(处理多语言切换)
|
|
|
|
|
'django.middleware.gzip.GZipMiddleware', # GZip 压缩中间件(减少响应体积)
|
|
|
|
|
# 'django.middleware.cache.UpdateCacheMiddleware', # 缓存更新中间件(注释:按需启用)
|
|
|
|
|
'django.middleware.common.CommonMiddleware', # 通用中间件(处理 URL 重定向、404 等)
|
|
|
|
|
# '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', # 条件请求中间件(缓存协商,减少重复请求)
|
|
|
|
|
'blog.middleware.OnlineMiddleware' # 自定义中间件:用户在线状态管理
|
|
|
|
|
|
|
|
|
|
'django.middleware.security.SecurityMiddleware',
|
|
|
|
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
|
|
|
'django.middleware.locale.LocaleMiddleware',
|
|
|
|
|
'django.middleware.gzip.GZipMiddleware',
|
|
|
|
|
# 'django.middleware.cache.UpdateCacheMiddleware',
|
|
|
|
|
'django.middleware.common.CommonMiddleware',
|
|
|
|
|
# 'django.middleware.cache.FetchFromCacheMiddleware',
|
|
|
|
|
'django.middleware.csrf.CsrfViewMiddleware',
|
|
|
|
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
|
|
|
'django.contrib.messages.middleware.MessageMiddleware',
|
|
|
|
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
|
|
|
'django.middleware.http.ConditionalGetMiddleware',
|
|
|
|
|
'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 目录加载模板
|
|
|
|
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
|
|
|
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
|
|
|
|
'APP_DIRS': True,
|
|
|
|
|
'OPTIONS': {
|
|
|
|
|
# 上下文处理器:向所有模板注入全局变量(如用户信息、请求对象)
|
|
|
|
|
'context_processors': [
|
|
|
|
|
'django.template.context_processors.debug', # 调试模式变量(如 DEBUG)
|
|
|
|
|
'django.template.context_processors.request', # 请求对象(request)
|
|
|
|
|
'django.contrib.auth.context_processors.auth', # 认证相关变量(如 user)
|
|
|
|
|
'django.contrib.messages.context_processors.messages', # 消息变量(如 messages)
|
|
|
|
|
'blog.context_processors.seo_processor' # 自定义上下文处理器:注入 SEO 相关数据
|
|
|
|
|
'django.template.context_processors.debug',
|
|
|
|
|
'django.template.context_processors.request',
|
|
|
|
|
'django.contrib.auth.context_processors.auth',
|
|
|
|
|
'django.contrib.messages.context_processors.messages',
|
|
|
|
|
'blog.context_processors.seo_processor'
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# WSGI 应用:指定项目的 WSGI 入口文件(用于部署,如 Gunicorn、uWSGI)
|
|
|
|
|
WSGI_APPLICATION = 'djangoblog.wsgi.application'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Database(数据库配置:使用 MySQL 数据库)
|
|
|
|
|
# Database
|
|
|
|
|
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 'root', # 数据库密码
|
|
|
|
|
'HOST': os.environ.get('DJANGO_MYSQL_HOST') or '127.0.0.1', # 数据库主机(默认本地)
|
|
|
|
|
'PORT': int(os.environ.get('DJANGO_MYSQL_PORT') or 3306), # 数据库端口(默认 3306)
|
|
|
|
|
'ENGINE': 'django.db.backends.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 'root',
|
|
|
|
|
'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 表情)
|
|
|
|
|
'charset': 'utf8mb4'},
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Password validation(密码验证规则:确保用户密码强度)
|
|
|
|
|
# Password validation
|
|
|
|
|
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
|
|
|
|
|
|
|
|
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
|
|
|
{
|
|
|
|
|
# 验证密码与用户属性(如用户名、邮箱)的相似度
|
|
|
|
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
# 验证密码最小长度(默认 8 位)
|
|
|
|
|
'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/1.10/topics/i18n/
|
|
|
|
|
LANGUAGES = (
|
|
|
|
|
('en', _('English')), # 英语
|
|
|
|
|
('zh-hans', _('Simplified Chinese')), # 简体中文
|
|
|
|
|
('zh-hant', _('Traditional Chinese')), # 繁体中文
|
|
|
|
|
('en', _('English')),
|
|
|
|
|
('zh-hans', _('Simplified Chinese')),
|
|
|
|
|
('zh-hant', _('Traditional Chinese')),
|
|
|
|
|
)
|
|
|
|
|
# 翻译文件目录:指定多语言翻译文件(.po/.mo)的存放路径
|
|
|
|
|
LOCALE_PATHS = (
|
|
|
|
|
os.path.join(BASE_DIR, 'locale'),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
LANGUAGE_CODE = 'zh-hans' # 默认语言:简体中文
|
|
|
|
|
TIME_ZONE = 'Asia/Shanghai' # 时区:上海(中国时区)
|
|
|
|
|
USE_I18N = True # 启用国际化(支持多语言)
|
|
|
|
|
USE_L10N = True # 启用本地化(支持区域化日期、数字格式)
|
|
|
|
|
USE_TZ = False # 禁用 UTC 时间(使用本地时区存储时间,避免时区转换问题)
|
|
|
|
|
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/1.10/howto/static-files/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Search(搜索框架配置:Haystack + Whoosh/Elasticsearch)
|
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
|
|
|
'default': {
|
|
|
|
|
# 搜索引擎:默认使用 Whoosh(轻量级全文搜索引擎,适合中小项目)
|
|
|
|
|
'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine',
|
|
|
|
|
# 索引文件路径:Whoosh 索引文件存储位置
|
|
|
|
|
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
# 实时更新索引:当模型数据(如文章)新增/修改/删除时,自动更新搜索索引
|
|
|
|
|
# Automatically update searching index
|
|
|
|
|
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Authentication(认证配置:自定义登录逻辑)
|
|
|
|
|
# 允许用户通过“用户名”或“邮箱”登录(默认仅支持用户名)
|
|
|
|
|
# Allow user login with username and password
|
|
|
|
|
AUTHENTICATION_BACKENDS = [
|
|
|
|
|
'accounts.user_login_backend.EmailOrUsernameModelBackend']
|
|
|
|
|
# 自定义用户模型:使用 accounts 应用的 BlogUser 模型(替代 Django 内置 User 模型)
|
|
|
|
|
|
|
|
|
|
STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
|
|
|
|
|
|
|
|
|
|
STATIC_URL = '/static/'
|
|
|
|
|
STATICFILES = os.path.join(BASE_DIR, 'static')
|
|
|
|
|
|
|
|
|
|
AUTH_USER_MODEL = 'accounts.BlogUser'
|
|
|
|
|
# 登录 URL:未登录用户访问需认证页面时,重定向到该 URL
|
|
|
|
|
LOGIN_URL = '/login/'
|
|
|
|
|
|
|
|
|
|
TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
|
|
|
|
DATE_TIME_FORMAT = '%Y-%m-%d'
|
|
|
|
|
|
|
|
|
|
# Custom Settings(自定义业务配置)
|
|
|
|
|
TIME_FORMAT = '%Y-%m-%d %H:%M:%S' # 时间显示格式(如 2024-05-20 14:30:00)
|
|
|
|
|
DATE_TIME_FORMAT = '%Y-%m-%d' # 日期显示格式(如 2024-05-20)
|
|
|
|
|
BOOTSTRAP_COLOR_TYPES = [ # Bootstrap 颜色样式(用于前端组件,如标签、按钮)
|
|
|
|
|
# bootstrap color styles
|
|
|
|
|
BOOTSTRAP_COLOR_TYPES = [
|
|
|
|
|
'default', 'primary', 'success', 'info', 'warning', 'danger'
|
|
|
|
|
]
|
|
|
|
|
PAGINATE_BY = 10 # 分页大小:每页显示 10 条数据(如文章列表、评论列表)
|
|
|
|
|
CACHE_CONTROL_MAX_AGE = 2592000 # HTTP 缓存有效期:30 天(单位:秒)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Cache(缓存配置:默认本地内存缓存,支持 Redis 扩展)
|
|
|
|
|
# paginate
|
|
|
|
|
PAGINATE_BY = 10
|
|
|
|
|
# http cache timeout
|
|
|
|
|
CACHE_CONTROL_MAX_AGE = 2592000
|
|
|
|
|
# cache setting
|
|
|
|
|
CACHES = {
|
|
|
|
|
'default': {
|
|
|
|
|
# 本地内存缓存(适合开发环境,生产环境建议用 Redis/Memcached)
|
|
|
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
|
|
|
'TIMEOUT': 10800, # 缓存有效期:3 小时(单位:秒)
|
|
|
|
|
'LOCATION': 'unique-snowflake', # 缓存实例标识(避免多实例冲突)
|
|
|
|
|
'TIMEOUT': 10800,
|
|
|
|
|
'LOCATION': 'unique-snowflake',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# 若环境变量指定 Redis 地址,则使用 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")}', # Redis 连接地址
|
|
|
|
|
'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Site & SEO(站点与 SEO 配置)
|
|
|
|
|
SITE_ID = 1 # 站点 ID(多站点配置时区分不同站点,单站点固定为 1)
|
|
|
|
|
# 百度主动推送 URL:用于文章发布后主动通知百度收录(提升 SEO 效率)
|
|
|
|
|
SITE_ID = 1
|
|
|
|
|
BAIDU_NOTIFY_URL = os.environ.get('DJANGO_BAIDU_NOTIFY_URL') \
|
|
|
|
|
or 'http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Email(邮件配置:用于发送验证码、评论通知等)
|
|
|
|
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # SMTP 邮件后端
|
|
|
|
|
EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False) # 是否启用 TLS 加密(与 SSL 二选一)
|
|
|
|
|
EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True) # 是否启用 SSL 加密(默认启用,端口通常为 465)
|
|
|
|
|
EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST') or 'smtp.mxhichina.com' # SMTP 服务器地址(默认阿里云)
|
|
|
|
|
EMAIL_PORT = int(os.environ.get('DJANGO_EMAIL_PORT') or 465) # SMTP 端口(SSL 通常为 465,TLS 通常为 587)
|
|
|
|
|
EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER') # 发送邮件的邮箱账号(优先环境变量)
|
|
|
|
|
EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD') # 邮箱密码/授权码
|
|
|
|
|
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER # 默认发件人邮箱
|
|
|
|
|
SERVER_EMAIL = EMAIL_HOST_USER # 服务器错误通知发件人邮箱
|
|
|
|
|
# 管理员邮箱:生产环境错误(如 500 异常)会发送到此邮箱
|
|
|
|
|
# Email:
|
|
|
|
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
|
|
|
EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False)
|
|
|
|
|
EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True)
|
|
|
|
|
EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST') or 'smtp.mxhichina.com'
|
|
|
|
|
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')
|
|
|
|
|
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
|
|
|
|
SERVER_EMAIL = EMAIL_HOST_USER
|
|
|
|
|
# Setting debug=false did NOT handle except email notifications
|
|
|
|
|
ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')]
|
|
|
|
|
# 微信管理员密码:二次 MD5 加密(用于微信后台管理验证,具体业务自定义)
|
|
|
|
|
# WX ADMIN password(Two times md5)
|
|
|
|
|
WXADMIN = os.environ.get(
|
|
|
|
|
'DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Logging(日志配置:记录系统操作、错误信息)
|
|
|
|
|
LOG_PATH = os.path.join(BASE_DIR, 'logs') # 日志文件目录
|
|
|
|
|
# 若日志目录不存在,则创建(确保日志能正常写入)
|
|
|
|
|
LOG_PATH = os.path.join(BASE_DIR, 'logs')
|
|
|
|
|
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'], # 日志处理器(控制台 + 文件)
|
|
|
|
|
'version': 1,
|
|
|
|
|
'disable_existing_loggers': False,
|
|
|
|
|
'root': {
|
|
|
|
|
'level': 'INFO',
|
|
|
|
|
'handlers': ['console', 'log_file'],
|
|
|
|
|
},
|
|
|
|
|
'formatters': { # 日志格式:定义日志的输出结构
|
|
|
|
|
'formatters': {
|
|
|
|
|
'verbose': {
|
|
|
|
|
# 日志格式:时间 + 级别 + 调用位置 + 消息(便于问题定位)
|
|
|
|
|
'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d %(module)s] %(message)s',
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'filters': { # 日志过滤器:按条件过滤日志
|
|
|
|
|
'require_debug_false': { # 仅当 DEBUG=False 时生效(生产环境)
|
|
|
|
|
'filters': {
|
|
|
|
|
'require_debug_false': {
|
|
|
|
|
'()': 'django.utils.log.RequireDebugFalse',
|
|
|
|
|
},
|
|
|
|
|
'require_debug_true': { # 仅当 DEBUG=True 时生效(开发环境)
|
|
|
|
|
'require_debug_true': {
|
|
|
|
|
'()': 'django.utils.log.RequireDebugTrue',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
'handlers': { # 日志处理器:定义日志的输出方式
|
|
|
|
|
'log_file': { # 文件处理器:按时间轮转切割日志
|
|
|
|
|
'handlers': {
|
|
|
|
|
'log_file': {
|
|
|
|
|
'level': 'INFO',
|
|
|
|
|
'class': 'logging.handlers.TimedRotatingFileHandler', # 按时间轮转的处理器
|
|
|
|
|
'filename': os.path.join(LOG_PATH, 'djangoblog.log'), # 日志文件路径
|
|
|
|
|
'when': 'D', # 轮转周期:每天(Day)
|
|
|
|
|
'formatter': 'verbose', # 使用 verbose 格式
|
|
|
|
|
'interval': 1, # 轮转间隔:1 个周期(1 天)
|
|
|
|
|
'delay': True, # 延迟创建文件(直到有日志才创建)
|
|
|
|
|
'backupCount': 5, # 保留日志备份数:5 天
|
|
|
|
|
'encoding': 'utf-8' # 日志文件编码
|
|
|
|
|
'class': 'logging.handlers.TimedRotatingFileHandler',
|
|
|
|
|
'filename': os.path.join(LOG_PATH, 'djangoblog.log'),
|
|
|
|
|
'when': 'D',
|
|
|
|
|
'formatter': 'verbose',
|
|
|
|
|
'interval': 1,
|
|
|
|
|
'delay': True,
|
|
|
|
|
'backupCount': 5,
|
|
|
|
|
'encoding': 'utf-8'
|
|
|
|
|
},
|
|
|
|
|
'console': { # 控制台处理器:开发环境输出到终端
|
|
|
|
|
'console': {
|
|
|
|
|
'level': 'DEBUG',
|
|
|
|
|
'filters': ['require_debug_true'], # 仅开发环境生效
|
|
|
|
|
'filters': ['require_debug_true'],
|
|
|
|
|
'class': 'logging.StreamHandler',
|
|
|
|
|
'formatter': 'verbose'
|
|
|
|
|
},
|
|
|
|
|
'null': { # 空处理器:用于屏蔽不需要的日志
|
|
|
|
|
'null': {
|
|
|
|
|
'class': 'logging.NullHandler',
|
|
|
|
|
},
|
|
|
|
|
'mail_admins': { # 邮件处理器:生产环境错误发送到管理员邮箱
|
|
|
|
|
'level': 'ERROR', # 仅 ERROR 级别日志触发
|
|
|
|
|
'filters': ['require_debug_false'], # 仅生产环境生效
|
|
|
|
|
'mail_admins': {
|
|
|
|
|
'level': 'ERROR',
|
|
|
|
|
'filters': ['require_debug_false'],
|
|
|
|
|
'class': 'django.utils.log.AdminEmailHandler'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
'loggers': { # 自定义日志器:针对特定模块配置日志
|
|
|
|
|
'djangoblog': { # 项目核心模块日志器
|
|
|
|
|
'handlers': ['log_file', 'console'], # 输出到文件和控制台
|
|
|
|
|
'loggers': {
|
|
|
|
|
'djangoblog': {
|
|
|
|
|
'handlers': ['log_file', 'console'],
|
|
|
|
|
'level': 'INFO',
|
|
|
|
|
'propagate': True, # 是否向上传递到根日志器(此处开启)
|
|
|
|
|
'propagate': True,
|
|
|
|
|
},
|
|
|
|
|
'django.request': { # Django 请求模块日志器(记录请求相关错误)
|
|
|
|
|
'handlers': ['mail_admins'], # 错误发送到管理员邮箱
|
|
|
|
|
'django.request': {
|
|
|
|
|
'handlers': ['mail_admins'],
|
|
|
|
|
'level': 'ERROR',
|
|
|
|
|
'propagate': False, # 不向上传递(避免重复记录)
|
|
|
|
|
'propagate': False,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Static Files(静态文件配置:CSS/JS/图片等)
|
|
|
|
|
# 静态文件收集目录:执行 collectstatic 命令后,静态文件会汇总到此处(生产环境使用)
|
|
|
|
|
STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
|
|
|
|
|
# 静态文件 URL 前缀:前端通过 /static/ 访问静态文件
|
|
|
|
|
STATIC_URL = '/static/'
|
|
|
|
|
# 全局静态文件目录:项目根目录下的 static 目录(存放全局静态文件)
|
|
|
|
|
STATICFILES = os.path.join(BASE_DIR, 'static')
|
|
|
|
|
|
|
|
|
|
# 静态文件查找器:指定 Django 查找静态文件的路径(内置 + 第三方)
|
|
|
|
|
STATICFILES_FINDERS = (
|
|
|
|
|
'django.contrib.staticfiles.finders.FileSystemFinder', # 查找全局 STATICFILES 目录
|
|
|
|
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 查找各应用的 static 目录
|
|
|
|
|
'compressor.finders.CompressorFinder', # 查找压缩后的静态文件(第三方 compressor 应用)
|
|
|
|
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
|
|
|
|
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
|
|
|
|
# other
|
|
|
|
|
'compressor.finders.CompressorFinder',
|
|
|
|
|
)
|
|
|
|
|
COMPRESS_ENABLED = True
|
|
|
|
|
# COMPRESS_OFFLINE = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 静态文件压缩配置(compressor 应用)
|
|
|
|
|
COMPRESS_ENABLED = True # 启用压缩(生产环境建议开启,提升加载速度)
|
|
|
|
|
# COMPRESS_OFFLINE = True # 离线压缩(预先生成压缩文件,生产环境推荐,此处注释按需启用)
|
|
|
|
|
# CSS 压缩过滤器:绝对路径处理 + 代码压缩
|
|
|
|
|
COMPRESS_CSS_FILTERS = [
|
|
|
|
|
# creates absolute urls from relative ones
|
|
|
|
|
'compressor.filters.css_default.CssAbsoluteFilter',
|
|
|
|
|
# css minimizer
|
|
|
|
|
'compressor.filters.cssmin.CSSMinFilter'
|
|
|
|
|
]
|
|
|
|
|
# JS 压缩过滤器:代码压缩
|
|
|
|
|
COMPRESS_JS_FILTERS = [
|
|
|
|
|
'compressor.filters.jsmin.JSMinFilter'
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Media Files(媒体文件配置:用户上传的文件,如文章图片、头像)
|
|
|
|
|
# 媒体文件存储目录:项目根目录下的 uploads 目录
|
|
|
|
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
|
|
|
|
|
# 媒体文件 URL 前缀:前端通过 /media/ 访问上传的文件
|
|
|
|
|
MEDIA_URL = '/media/'
|
|
|
|
|
|
|
|
|
|
# X-Frame-Options:防止点击劫持(SAMEORIGIN:仅允许同域页面嵌入当前页面)
|
|
|
|
|
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
|
|
|
|
|
|
|
|
|
# 默认模型主键类型:Django 3.2+ 新增,指定模型默认主键为 BigAutoField(64 位自增整数)
|
|
|
|
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Elasticsearch 配置(按需启用:若环境变量指定 Elasticsearch 地址,则使用 Elasticsearch 替代 Whoosh)
|
|
|
|
|
if os.environ.get('DJANGO_ELASTICSEARCH_HOST'):
|
|
|
|
|
ELASTICSEARCH_DSL = {
|
|
|
|
|
'default': {
|
|
|
|
|
'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST') # Elasticsearch 连接地址
|
|
|
|
|
'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST')
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
# 替换 Haystack 搜索引擎为自定义的 Elasticsearch 引擎
|
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
|
|
|
'default': {
|
|
|
|
|
'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine',
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Plugin System(插件系统配置:自定义插件功能)
|
|
|
|
|
PLUGINS_DIR = BASE_DIR / 'plugins' # 插件目录:项目根目录下的 plugins 目录
|
|
|
|
|
# 激活的插件列表:指定需要加载的插件(如文章版权、阅读时长统计等)
|
|
|
|
|
# Plugin System
|
|
|
|
|
PLUGINS_DIR = BASE_DIR / 'plugins'
|
|
|
|
|
ACTIVE_PLUGINS = [
|
|
|
|
|
'article_copyright', # 文章版权插件
|
|
|
|
|
'reading_time', # 阅读时长统计插件
|
|
|
|
|
'external_links', # 外部链接处理插件
|
|
|
|
|
'view_count', # 文章阅读量统计插件
|
|
|
|
|
'seo_optimizer' # SEO 优化插件
|
|
|
|
|
'article_copyright',
|
|
|
|
|
'reading_time',
|
|
|
|
|
'external_links',
|
|
|
|
|
'view_count',
|
|
|
|
|
'seo_optimizer'
|
|
|
|
|
]
|