You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tentest/doc/DjangoBlog/djangoblog/settings.py

436 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
Django settings for djangoblog project.
项目基本配置文件包含Django运行所需的核心配置项
Generated by 'django-admin startproject' using Django 1.10.2.
基于Django 1.10.2版本创建
For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""
#wr 导入必要模块
import os
import sys
from pathlib import Path # 用于路径处理的现代工具
from django.utils.translation import gettext_lazy as _ # 国际化翻译工具
def env_to_bool(env, default):
"""
将环境变量值转换为布尔值
:param env: 环境变量名称
:param default: 当环境变量不存在时的默认值
:return: 转换后的布尔值(环境变量为'True'时返回True否则返回default
"""
str_val = os.environ.get(env)
return default if str_val is None else str_val == 'True'
#wr 项目路径配置
# 构建项目内部路径BASE_DIR / 'subdir'
BASE_DIR = Path(__file__).resolve().parent.parent # 项目根目录(当前文件的父级父级目录)
#wr 快速开发设置 - 不适用于生产环境
# 安全警告:生产环境中必须保护好密钥
SECRET_KEY = os.environ.get(
'DJANGO_SECRET_KEY') or 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6'
# 优先从环境变量获取密钥,不存在则使用默认(仅开发环境用)
# 安全警告:生产环境必须关闭调试模式
DEBUG = env_to_bool('DJANGO_DEBUG', True) # 调试模式开关,默认开启
# DEBUG = False # 生产环境关闭调试的示例
#wr 测试模式判断:当执行命令包含'test'时视为测试环境
TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'
#wr 允许访问的主机列表(生产环境需指定具体域名,不可用'*'
# ALLOWED_HOSTS = [] # 默认空列表(仅允许本地访问)
ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com'] # 开发环境允许所有主机访问
#wr Django 4.0新增配置信任的CSRF来源跨域请求时需要
CSRF_TRUSTED_ORIGINS = ['http://example.com']
#wr 应用定义安装的所有Django应用
INSTALLED_APPS = [
# 'django.contrib.admin', # 默认管理员界面(全功能版)
'django.contrib.admin.apps.SimpleAdminConfig', # 简化版管理员界面
'django.contrib.auth', # 身份认证系统
'django.contrib.contenttypes', # 内容类型框架(用于权限管理)
'django.contrib.sessions', # 会话管理
'django.contrib.messages', # 消息提示系统
'django.contrib.staticfiles', # 静态文件管理
'django.contrib.sites', # 多站点支持框架
'django.contrib.sitemaps', # 站点地图生成
'mdeditor', # Markdown编辑器第三方应用
'haystack', # 全文搜索框架(第三方应用)
'blog', # 自定义博客应用
'accounts', # 自定义用户账户应用
'comments', # 自定义评论应用
'oauth', # 第三方登录OAuth应用
'servermanager', # 服务器管理应用
'owntracks', # 位置追踪应用
'compressor', # 静态文件压缩工具(第三方应用)
'djangoblog' # 项目主应用
]
#wr 中间件配置(请求/响应处理的钩子函数)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', # 安全相关处理如HTTPS重定向
'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', # 处理条件请求如304响应
'blog.middleware.OnlineMiddleware' # 自定义在线状态中间件
]
#wr URL根配置
ROOT_URLCONF = 'djangoblog.urls' # 主URL配置模块路径
#wr 模板配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates', # 使用Django模板引擎
'DIRS': [os.path.join(BASE_DIR, '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', # 认证相关上下文
'django.contrib.messages.context_processors.messages', # 消息相关上下文
'blog.context_processors.seo_processor' # 自定义SEO相关上下文
],
},
},
]
#wr WSGI应用配置部署用
WSGI_APPLICATION = 'djangoblog.wsgi.application' # WSGI应用入口路径
wr# 数据库配置
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
'OPTIONS': {
'charset': 'utf8mb4'}, # 字符集支持emoji表情
}}
#wr 密码验证配置
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
# 验证密码与用户属性(如用户名、邮箱)的相似度
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
# 验证密码最小长度默认8位
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
# 验证密码是否在常见密码列表中
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
# 验证密码是否仅包含数字
},
]
#wr 国际化配置
LANGUAGES = (
('en', _('English')), # 英语
('zh-hans', _('Simplified Chinese')), # 简体中文
('zh-hant', _('Traditional Chinese')), # 繁体中文
)
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时区使用本地时区
#wr 静态文件配置CSS、JavaScript、图片等
#wr 全文搜索配置基于Haystack框架
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine', # 使用Whoosh搜索引擎支持中文
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'), # 索引文件存储路径
},
}
#wr 实时更新搜索索引(当数据变化时自动更新)
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
#wr 认证后端:允许使用用户名或邮箱登录
AUTHENTICATION_BACKENDS = [
'accounts.user_login_backend.EmailOrUsernameModelBackend']
#wr 静态文件收集目录生产环境用通过collectstatic命令收集
STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
#wr 静态文件URL前缀
STATIC_URL = '/static/'
#wr 静态文件主目录
STATICFILES = os.path.join(BASE_DIR, 'static')
#wr 额外的静态文件目录(如插件静态文件)
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'plugins'), # 插件静态文件目录
]
#wr 自定义用户模型替换Django默认用户模型
AUTH_USER_MODEL = 'accounts.BlogUser'
# 登录页面URL未登录时访问受保护页面会重定向到此处
LOGIN_URL = '/login/'
#wr 时间格式配置(模板中使用)
TIME_FORMAT = '%Y-%m-%d %H:%M:%S' # 完整时间格式
DATE_TIME_FORMAT = '%Y-%m-%d' # 日期格式
#wr Bootstrap样式颜色类型前端样式用
BOOTSTRAP_COLOR_TYPES = [
'default', 'primary', 'success', 'info', 'warning', 'danger'
]
#wr 分页配置
PAGINATE_BY = 10 # 每页显示10条数据
#wr HTTP缓存超时时间2592000 = 30天
CACHE_CONTROL_MAX_AGE = 2592000
#wr 缓存配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 本地内存缓存
'TIMEOUT': 10800, # 缓存超时时间10800 = 3小时
'LOCATION': 'unique-snowflake', # 缓存位置标识(唯一即可)
}
}
#wr 若存在Redis环境变量则使用Redis作为缓存
if os.environ.get("DJANGO_REDIS_URL"):
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache', # Redis缓存引擎
'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}', # Redis连接地址
}
}
#wr 站点框架配置(用于多站点管理)
SITE_ID = 1
#wr 百度链接提交API地址用于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'
#wr 邮件配置(用于发送通知、验证码等)
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # SMTP邮件后端
EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False) # 是否使用TLS加密
EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True) # 是否使用SSL加密
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 # 服务器发件人(用于错误报告)
#wr 管理员邮箱(用于接收系统错误报告)
ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')]
#wr 微信管理员密码二次MD5加密
WXADMIN = os.environ.get(
'DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7'
#wr 日志配置
LOG_PATH = os.path.join(BASE_DIR, 'logs') # 日志文件存储目录
#wr 若日志目录不存在则创建
if not os.path.exists(LOG_PATH):
os.makedirs(LOG_PATH, exist_ok=True)
LOGGING = {
'version': 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': { # 仅当DEBUG=False时生效
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': { # 仅当DEBUG=True时生效
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 日志处理器
'log_file': { # 文件处理器
'level': 'INFO', # 处理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', # 处理DEBUG及以上级别
'filters': ['require_debug_true'], # 仅调试模式生效
'class': 'logging.StreamHandler', # 流处理器(输出到控制台)
'formatter': 'verbose' # 使用详细格式
},
'null': { # 空处理器(不处理日志)
'class': 'logging.NullHandler',
},
'mail_admins': { # 邮件通知处理器
'level': 'ERROR', # 仅处理ERROR及以上级别
'filters': ['require_debug_false'], # 仅生产环境生效
'class': 'django.utils.log.AdminEmailHandler' # 发送邮件给管理员
}
},
'loggers': { # 日志器
'djangoblog': { # 项目主日志器
'handlers': ['log_file', 'console'], # 使用文件和控制台处理器
'level': 'INFO', # 日志级别
'propagate': True, # 是否向上传播日志
}
}
}
#wr 静态文件压缩配置使用django-compressor
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder', # 从文件系统查找静态文件
'django.contrib.staticfiles.finders.AppDirectoriesFinder', # 从应用目录查找静态文件
'compressor.finders.CompressorFinder', # 压缩器查找器
)
COMPRESS_ENABLED = True # 启用压缩
#wr 根据环境变量决定是否启用离线压缩(预压缩静态文件)
COMPRESS_OFFLINE = os.environ.get('COMPRESS_OFFLINE', 'False').lower() == 'true'
#wr 压缩文件输出目录
COMPRESS_OUTPUT_DIR = 'compressed'
#wr 压缩文件名包含哈希值(用于缓存失效)
COMPRESS_CSS_HASHING_METHOD = 'mtime' # 基于修改时间生成哈希
COMPRESS_JS_HASHING_METHOD = 'mtime'
#wr CSS压缩过滤器
COMPRESS_CSS_FILTERS = [
'compressor.filters.css_default.CssAbsoluteFilter', # 转换为绝对URL
'compressor.filters.cssmin.CSSCompressorFilter', # CSS压缩
]
#wr JS压缩过滤器
COMPRESS_JS_FILTERS = [
'compressor.filters.jsmin.SlimItFilter', # JS压缩
]
#wr 压缩缓存配置
COMPRESS_CACHE_BACKEND = 'default' # 使用默认缓存
COMPRESS_CACHE_KEY_FUNCTION = 'compressor.cache.simple_cachekey' # 缓存键生成函数
#wr 预编译配置处理Sass/SCSS
COMPRESS_PRECOMPILERS = (
('text/x-scss', 'django_libsass.SassCompiler'), # 编译SCSS
('text/x-sass', 'django_libsass.SassCompiler'), # 编译Sass
)
#wr 压缩性能优化
COMPRESS_MINT_DELAY = 30 # 压缩延迟(秒)
COMPRESS_MTIME_DELAY = 10 # 修改时间检查延迟
COMPRESS_REBUILD_TIMEOUT = 2592000 # 重建超时30天
#wr 压缩器配置
COMPRESS_CSS_COMPRESSOR = 'compressor.css.CssCompressor' # CSS压缩器
COMPRESS_JS_COMPRESSOR = 'compressor.js.JsCompressor' # JS压缩器
#wr 静态文件缓存配置(文件名包含哈希,用于缓存破坏)
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
#wr 压缩文件URL和根目录与静态文件一致
COMPRESS_URL = STATIC_URL
COMPRESS_ROOT = STATIC_ROOT
#wr 媒体文件配置(用户上传文件)
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') # 上传文件存储目录
MEDIA_URL = '/media/' # 媒体文件URL前缀
#wr X-Frame-Options配置允许同源页面嵌入iframe如Markdown编辑器预览
X_FRAME_OPTIONS = 'SAMEORIGIN'
#wr 默认自增字段类型Django 3.2+新增)
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # 使用BigInt类型自增ID
#wr Elasticsearch配置若存在环境变量则启用
if os.environ.get('DJANGO_ELASTICSEARCH_HOST'):
ELASTICSEARCH_DSL = {
'default': {
'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST') # Elasticsearch地址
},
}
#wr 替换Haystack引擎为Elasticsearch
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine',
},
}
#wr 插件系统配置
PLUGINS_DIR = BASE_DIR / 'plugins' # 插件目录
ACTIVE_PLUGINS = [ # 激活的插件列表
'article_copyright', # 文章版权信息插件
'reading_time', # 阅读时间估算插件
'external_links', # 外部链接处理插件
'view_count', # 浏览量统计插件
'seo_optimizer', # SEO优化插件
'image_lazy_loading', # 图片懒加载插件
'article_recommendation', # 文章推荐插件
]