diff --git a/djangoblog/settings.py b/djangoblog/settings.py index 33e3496b..416148e3 100644 --- a/djangoblog/settings.py +++ b/djangoblog/settings.py @@ -17,109 +17,99 @@ from django.utils.translation import gettext_lazy as _ def env_to_bool(env, default): + """将环境变量值转换为布尔值的工具函数""" str_val = os.environ.get(env) return default if str_val is None else str_val == 'True' -# Build paths inside the project like this: BASE_DIR / 'subdir'. +#姜雨菲: 构建项目路径,BASE_DIR为项目根目录 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/ - -# SECURITY WARNING: keep the secret key used in production secret! +#姜雨菲: 快速开发设置 - 不适用于生产环境 +# 安全警告:生产环境中请保持SECRET_KEY的机密性! 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模式 DEBUG = env_to_bool('DJANGO_DEBUG', True) -# DEBUG = False +# 测试环境标识,当执行测试命令时为True TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test' -# ALLOWED_HOSTS = [] +# 允许访问的主机,生产环境需配置具体域名 ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com'] -# django 4.0新增配置 +# Django 4.0新增配置,指定可信任的CSRF来源 CSRF_TRUSTED_ORIGINS = ['http://example.com'] -# Application definition - +# 应用定义 INSTALLED_APPS = [ - # 'django.contrib.admin', + # 自定义的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', - 'haystack', - 'blog', - 'accounts', - 'comments', - 'oauth', - 'servermanager', - 'owntracks', - 'compressor', - 'djangoblog' + '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', # 第三方登录应用 + 'servermanager', # 服务器管理应用 + 'owntracks', # 位置追踪应用 + 'compressor', # 静态文件压缩应用 + 'djangoblog' # 项目主应用 ] MIDDLEWARE = [ - - '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' + 'django.middleware.security.SecurityMiddleware', # 安全中间件(处理HTTPS等安全相关) + 'django.contrib.sessions.middleware.SessionMiddleware', # 会话中间件 + 'django.middleware.locale.LocaleMiddleware', # 国际化中间件(语言切换) + 'django.middleware.gzip.GZipMiddleware', # GZip压缩中间件 + 'django.middleware.common.CommonMiddleware', # 通用中间件(处理请求/响应) + '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' # 自定义在线用户统计中间件 ] -ROOT_URLCONF = 'djangoblog.urls' +ROOT_URLCONF = 'djangoblog.urls' # 项目URL配置入口 TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')], - 'APP_DIRS': True, + 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 模板引擎 + 'DIRS': [os.path.join(BASE_DIR, 'templates')], # 自定义模板目录 + 'APP_DIRS': True, # 是否自动搜索应用内的templates目录 'OPTIONS': { - 'context_processors': [ + 'context_processors': [ # 模板上下文处理器 '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' + 'blog.context_processors.seo_processor' # 自定义SEO上下文处理器 ], }, }, ] -WSGI_APPLICATION = 'djangoblog.wsgi.application' - -# Database -# https://docs.djangoproject.com/en/1.10/ref/settings/#databases - +WSGI_APPLICATION = 'djangoblog.wsgi.application' # WSGI应用入口 +# 数据库配置 DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'djangoblog', - 'USER': 'root', - 'PASSWORD': '050807', - 'HOST': '127.0.0.1', - 'PORT': 3306, + 'ENGINE': 'django.db.backends.mysql', # 使用MySQL数据库引擎 + 'NAME': 'djangoblog', # 数据库名 + 'USER': 'root', # 数据库用户名 + 'PASSWORD': '050807', # 数据库密码 + 'HOST': '127.0.0.1', # 数据库主机 + 'PORT': 3306, # 数据库端口 } } -# Password validation -# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators - +# 密码验证配置 AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', @@ -135,75 +125,72 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +# 支持的语言列表(国际化配置) 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 - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.10/howto/static-files/ - +LANGUAGE_CODE = 'zh-hans' # 默认语言 +TIME_ZONE = 'Asia/Shanghai' # 时区 +USE_I18N = True # 启用国际化 +USE_L10N = True # 启用本地化格式 +USE_TZ = False # 不使用时区感知模型 +# 搜索框架Haystack配置 HAYSTACK_CONNECTIONS = { 'default': { - 'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine', - 'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'), + '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' -# Allow user login with username and password +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' # 实时信号处理器(自动更新索引) + +# 认证后端配置(支持用户名或邮箱登录) AUTHENTICATION_BACKENDS = [ 'accounts.user_login_backend.EmailOrUsernameModelBackend'] -STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic') +# 静态文件配置 +STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic') # 静态文件收集目录(生产环境用) +STATIC_URL = '/static/' # 静态文件URL前缀 +STATICFILES = os.path.join(BASE_DIR, 'static') # 静态文件源目录 -STATIC_URL = '/static/' -STATICFILES = os.path.join(BASE_DIR, 'static') - -# 添加插件静态文件目录 +# 插件静态文件目录 STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'plugins'), # 让Django能找到插件的静态文件 + os.path.join(BASE_DIR, 'plugins'), # 插件静态文件目录 ] -AUTH_USER_MODEL = 'accounts.BlogUser' -LOGIN_URL = '/login/' +AUTH_USER_MODEL = 'accounts.BlogUser' # 自定义用户模型 +LOGIN_URL = '/login/' # 登录URL +# 时间格式定义 TIME_FORMAT = '%Y-%m-%d %H:%M:%S' DATE_TIME_FORMAT = '%Y-%m-%d' -# bootstrap color styles +# Bootstrap颜色样式 BOOTSTRAP_COLOR_TYPES = [ 'default', 'primary', 'success', 'info', 'warning', 'danger' ] -# paginate +# 分页配置 PAGINATE_BY = 10 -# http cache timeout +# HTTP缓存超时时间(秒) CACHE_CONTROL_MAX_AGE = 2592000 -# cache setting + +# 缓存配置 CACHES = { 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - 'TIMEOUT': 10800, - 'LOCATION': 'unique-snowflake', + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 本地内存缓存 + 'TIMEOUT': 10800, # 缓存超时时间(秒) + 'LOCATION': 'unique-snowflake', # 缓存位置标识 } } -# 使用redis作为缓存 +# 若存在环境变量,则使用Redis作为缓存 if os.environ.get("DJANGO_REDIS_URL"): CACHES = { 'default': { @@ -212,26 +199,28 @@ if os.environ.get("DJANGO_REDIS_URL"): } } -SITE_ID = 1 +SITE_ID = 1 # 站点ID(多站点时使用) +# 百度链接提交通知URL 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' -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 +# 邮件配置 +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 # 服务器邮件发件人 +# 管理员邮件通知配置 ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')] -# WX ADMIN password(Two times md5) +# 微信管理密码(两次MD5加密) WXADMIN = os.environ.get( 'DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7' +# 日志配置 LOG_PATH = os.path.join(BASE_DIR, 'logs') if not os.path.exists(LOG_PATH): os.makedirs(LOG_PATH, exist_ok=True) @@ -297,74 +286,67 @@ LOGGING = { } } +# 静态文件查找器(用于Compressor) STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # other 'compressor.finders.CompressorFinder', ) -COMPRESS_ENABLED = True +COMPRESS_ENABLED = True # 启用静态文件压缩 # 根据环境变量决定是否启用离线压缩 COMPRESS_OFFLINE = os.environ.get('COMPRESS_OFFLINE', 'False').lower() == 'true' -# 压缩输出目录 -COMPRESS_OUTPUT_DIR = 'compressed' +COMPRESS_OUTPUT_DIR = 'compressed' # 压缩文件输出目录 +COMPRESS_CSS_HASHING_METHOD = 'mtime' # CSS哈希生成方式(基于修改时间) +COMPRESS_JS_HASHING_METHOD = 'mtime' # JS哈希生成方式(基于修改时间) -# 压缩文件名模板 - 包含哈希值用于缓存破坏 -COMPRESS_CSS_HASHING_METHOD = 'mtime' -COMPRESS_JS_HASHING_METHOD = 'mtime' - -# 高级CSS压缩过滤器 +# CSS压缩过滤器 COMPRESS_CSS_FILTERS = [ - # 创建绝对URL - 'compressor.filters.css_default.CssAbsoluteFilter', - # CSS压缩器 - 高压缩等级 - 'compressor.filters.cssmin.CSSCompressorFilter', + 'compressor.filters.css_default.CssAbsoluteFilter', # 处理CSS中的绝对URL + 'compressor.filters.cssmin.CSSCompressorFilter', # CSS压缩器 ] -# 高级JS压缩过滤器 +# JS压缩过滤器 COMPRESS_JS_FILTERS = [ - # JS压缩器 - 高压缩等级 - 'compressor.filters.jsmin.SlimItFilter', + 'compressor.filters.jsmin.SlimItFilter', # JS压缩器 ] -# 压缩缓存配置 -COMPRESS_CACHE_BACKEND = 'default' -COMPRESS_CACHE_KEY_FUNCTION = 'compressor.cache.simple_cachekey' +COMPRESS_CACHE_BACKEND = 'default' # 压缩缓存后端 +COMPRESS_CACHE_KEY_FUNCTION = 'compressor.cache.simple_cachekey' # 缓存键生成函数 -# 预压缩配置 +# 预编译器配置(支持SCSS/SASS) COMPRESS_PRECOMPILERS = ( - # 支持SCSS/SASS ('text/x-scss', 'django_libsass.SassCompiler'), ('text/x-sass', 'django_libsass.SassCompiler'), ) -# 压缩性能优化 -COMPRESS_MINT_DELAY = 30 # 压缩延迟(秒) -COMPRESS_MTIME_DELAY = 10 # 修改时间检查延迟 -COMPRESS_REBUILD_TIMEOUT = 2592000 # 重建超时(30天) +# 压缩性能优化配置 +COMPRESS_MINT_DELAY = 30 +COMPRESS_MTIME_DELAY = 10 +COMPRESS_REBUILD_TIMEOUT = 2592000 -# 压缩等级配置 COMPRESS_CSS_COMPRESSOR = 'compressor.css.CssCompressor' COMPRESS_JS_COMPRESSOR = 'compressor.js.JsCompressor' -# 静态文件缓存配置 +# 静态文件存储(带Manifest用于缓存破坏) STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage' -# 浏览器缓存配置(通过中间件或服务器配置) COMPRESS_URL = STATIC_URL COMPRESS_ROOT = STATIC_ROOT +# 媒体文件(用户上传文件)配置 MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') MEDIA_URL = '/media/' + +# XFrameOptions配置(允许同域iframe) X_FRAME_OPTIONS = 'SAMEORIGIN' -# 安全头部配置 - 防XSS和其他攻击 -SECURE_BROWSER_XSS_FILTER = True -SECURE_CONTENT_TYPE_NOSNIFF = True -SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin' +# 安全头部配置 +SECURE_BROWSER_XSS_FILTER = True # 启用XSS过滤 +SECURE_CONTENT_TYPE_NOSNIFF = True # 禁止内容类型嗅探 +SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin' # Referrer策略 -# 内容安全策略 (CSP) - 防XSS攻击 +# 内容安全策略(CSP) CSP_DEFAULT_SRC = ["'self'"] CSP_SCRIPT_SRC = ["'self'", "'unsafe-inline'", "cdn.mathjax.org", "*.googleapis.com"] CSP_STYLE_SRC = ["'self'", "'unsafe-inline'", "*.googleapis.com", "*.gstatic.com"] @@ -374,8 +356,9 @@ CSP_CONNECT_SRC = ["'self'"] CSP_FRAME_SRC = ["'none'"] CSP_OBJECT_SRC = ["'none'"] -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # 默认自增字段类型 +# 若存在环境变量,则使用Elasticsearch作为搜索后端 if os.environ.get('DJANGO_ELASTICSEARCH_HOST'): ELASTICSEARCH_DSL = { 'default': { @@ -388,15 +371,14 @@ if os.environ.get('DJANGO_ELASTICSEARCH_HOST'): }, } -# Plugin System +# 插件系统配置 PLUGINS_DIR = BASE_DIR / 'plugins' ACTIVE_PLUGINS = [ - 'article_copyright', - 'reading_time', - 'external_links', - 'view_count', - 'seo_optimizer', - 'image_lazy_loading', - 'article_recommendation', -] - + 'article_copyright', # 文章版权插件 + 'reading_time', # 阅读时间插件 + 'external_links', # 外部链接插件 + 'view_count', # 阅读计数插件 + 'seo_optimizer', # SEO优化插件 + 'image_lazy_loading', # 图片懒加载插件 + 'article_recommendation', # 文章推荐插件 +] \ No newline at end of file