master
ZXY 1 month ago
parent 5b0854e397
commit 2e62fc2db4

@ -1 +1,2 @@
# Zxy指定默认的应用配置类
default_app_config = 'djangoblog.apps.DjangoblogAppConfig'

@ -1,8 +1,10 @@
# Zxy导入 Django 的 AdminSite 类和其他相关模块
from django.contrib.admin import AdminSite
from django.contrib.admin.models import LogEntry
from django.contrib.sites.admin import SiteAdmin
from django.contrib.sites.models import Site
# Zxy导入自定义模块和模型
from accounts.admin import *
from blog.admin import *
from blog.models import *
@ -16,31 +18,25 @@ from owntracks.models import *
from servermanager.admin import *
from servermanager.models import *
# Zxy定义自定义 AdminSite 类
class DjangoBlogAdminSite(AdminSite):
# 自定义站点标题和头部
site_header = 'djangoblog administration'
site_title = 'djangoblog site admin'
# 初始化方法
def __init__(self, name='admin'):
super().__init__(name)
# 定义权限检查方法,仅允许超级用户访问
def has_permission(self, request):
return request.user.is_superuser
# def get_urls(self):
# urls = super().get_urls()
# from django.urls import path
# from blog.views import refresh_memcache
#
# my_urls = [
# path('refresh/', self.admin_view(refresh_memcache), name="refresh"),
# ]
# return urls + my_urls
# Zxy创建自定义 AdminSite 实例
admin_site = DjangoBlogAdminSite(name='admin')
admin_site.register(Article, ArticlelAdmin)
# Zxy注册模型到自定义 AdminSite
admin_site.register(Article, ArticleAdmin)
admin_site.register(Category, CategoryAdmin)
admin_site.register(Tag, TagAdmin)
admin_site.register(Links, LinksAdmin)
@ -61,4 +57,4 @@ admin_site.register(OwnTrackLog, OwnTrackLogsAdmin)
admin_site.register(Site, SiteAdmin)
admin_site.register(LogEntry, LogEntryAdmin)
admin_site.register(LogEntry, LogEntryAdmin)

@ -1,11 +1,16 @@
# Zxy导入Django的AppConfig模块
from django.apps import AppConfig
# Zxy定义Djangoblog应用的配置类
class DjangoblogAppConfig(AppConfig):
# Zxy设置默认的自动字段类型
default_auto_field = 'django.db.models.BigAutoField'
# Zxy应用名称
name = 'djangoblog'
# Zxy重写ready方法用于初始化应用
def ready(self):
super().ready()
# Import and load plugins here
super().ready() # Zxy调用父类的ready方法
# Zxy导入并加载插件
from .plugin_manage.loader import load_plugins
load_plugins()
load_plugins() # Zxy加载插件

@ -1,122 +1,133 @@
# Zxy导入线程模块
import _thread
# Zxy导入日志模块
import logging
# Zxy导入Django的信号模块
import django.dispatch
# Zxy导入Django的配置模块
from django.conf import settings
# Zxy导入Django的LogEntry模型
from django.contrib.admin.models import LogEntry
# Zxy导入用户登录和登出信号
from django.contrib.auth.signals import user_logged_in, user_logged_out
# Zxy导入邮件发送模块
from django.core.mail import EmailMultiAlternatives
# Zxy导入模型保存信号
from django.db.models.signals import post_save
# Zxy导入信号接收器
from django.dispatch import receiver
# Zxy导入评论模型
from comments.models import Comment
# Zxy导入发送评论邮件的工具函数
from comments.utils import send_comment_email
# Zxy导入爬虫通知工具
from djangoblog.spider_notify import SpiderNotify
# Zxy导入缓存和缓存清理工具
from djangoblog.utils import cache, expire_view_cache, delete_sidebar_cache, delete_view_cache
# Zxy导入获取当前站点的工具函数
from djangoblog.utils import get_current_site
# Zxy导入OAuth用户模型
from oauth.models import OAuthUser
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy定义OAuth用户登录信号
oauth_user_login_signal = django.dispatch.Signal(['id'])
send_email_signal = django.dispatch.Signal(
['emailto', 'title', 'content'])
# Zxy定义发送邮件信号
send_email_signal = django.dispatch.Signal(['emailto', 'title', 'content'])
# Zxy定义发送邮件信号的处理函数
@receiver(send_email_signal)
def send_email_signal_handler(sender, **kwargs):
emailto = kwargs['emailto']
title = kwargs['title']
content = kwargs['content']
emailto = kwargs['emailto'] # Zxy收件人
title = kwargs['title'] # Zxy邮件标题
content = kwargs['content'] # Zxy邮件内容
msg = EmailMultiAlternatives(
msg = EmailMultiAlternatives( # Zxy创建邮件对象
title,
content,
from_email=settings.DEFAULT_FROM_EMAIL,
to=emailto)
msg.content_subtype = "html"
from_email=settings.DEFAULT_FROM_EMAIL, # Zxy发件人
to=emailto # Zxy收件人
)
msg.content_subtype = "html" # Zxy设置邮件内容类型为HTML
from servermanager.models import EmailSendLog
log = EmailSendLog()
from servermanager.models import EmailSendLog # Zxy导入邮件发送日志模型
log = EmailSendLog() # Zxy创建日志记录
log.title = title
log.content = content
log.emailto = ','.join(emailto)
log.emailto = ','.join(emailto) # Zxy记录收件人
try:
result = msg.send()
log.send_result = result > 0
result = msg.send() # Zxy发送邮件
log.send_result = result > 0 # Zxy记录发送结果
except Exception as e:
logger.error(f"失败邮箱号: {emailto}, {e}")
logger.error(f"失败邮箱号: {emailto}, {e}") # Zxy记录错误信息
log.send_result = False
log.save()
log.save() # Zxy保存日志
# Zxy定义OAuth用户登录信号的处理函数
@receiver(oauth_user_login_signal)
def oauth_user_login_signal_handler(sender, **kwargs):
id = kwargs['id']
oauthuser = OAuthUser.objects.get(id=id)
site = get_current_site().domain
if oauthuser.picture and not oauthuser.picture.find(site) >= 0:
from djangoblog.utils import save_user_avatar
oauthuser.picture = save_user_avatar(oauthuser.picture)
oauthuser.save()
delete_sidebar_cache()
id = kwargs['id'] # Zxy获取用户ID
oauthuser = OAuthUser.objects.get(id=id) # Zxy获取OAuth用户
site = get_current_site().domain # Zxy获取当前站点域名
if oauthuser.picture and not oauthuser.picture.find(site) >= 0: # Zxy检查头像URL是否包含当前站点域名
from djangoblog.utils import save_user_avatar # Zxy导入保存头像的工具函数
oauthuser.picture = save_user_avatar(oauthuser.picture) # Zxy保存用户头像
oauthuser.save() # Zxy保存用户信息
delete_sidebar_cache() # Zxy删除侧边栏缓存
# Zxy定义模型保存后的回调函数
@receiver(post_save)
def model_post_save_callback(
sender,
instance,
created,
raw,
using,
update_fields,
**kwargs):
clearcache = False
if isinstance(instance, LogEntry):
def model_post_save_callback(sender, instance, created, raw, using, update_fields, **kwargs):
clearcache = False # Zxy标记是否需要清理缓存
if isinstance(instance, LogEntry): # Zxy如果是LogEntry模型直接返回
return
if 'get_full_url' in dir(instance):
is_update_views = update_fields == {'views'}
if not settings.TESTING and not is_update_views:
if 'get_full_url' in dir(instance): # Zxy检查是否有获取完整URL的方法
is_update_views = update_fields == {'views'} # Zxy检查是否是更新浏览次数
if not settings.TESTING and not is_update_views: # Zxy如果不是测试环境且不是更新浏览次数
try:
notify_url = instance.get_full_url()
SpiderNotify.baidu_notify([notify_url])
notify_url = instance.get_full_url() # Zxy获取完整URL
SpiderNotify.baidu_notify([notify_url]) # Zxy通知百度爬虫
except Exception as ex:
logger.error("notify sipder", ex)
logger.error("notify spider", ex) # Zxy记录错误信息
if not is_update_views:
clearcache = True
clearcache = True # Zxy标记清理缓存
if isinstance(instance, Comment):
if instance.is_enable:
path = instance.article.get_absolute_url()
site = get_current_site().domain
if site.find(':') > 0:
if isinstance(instance, Comment): # Zxy如果是评论模型
if instance.is_enable: # Zxy检查评论是否启用
path = instance.article.get_absolute_url() # Zxy获取文章的绝对URL
site = get_current_site().domain # Zxy获取当前站点域名
if site.find(':') > 0: # Zxy去除端口号
site = site[0:site.find(':')]
expire_view_cache(
expire_view_cache( # Zxy清理视图缓存
path,
servername=site,
serverport=80,
key_prefix='blogdetail')
if cache.get('seo_processor'):
key_prefix='blogdetail'
)
if cache.get('seo_processor'): # Zxy清理SEO处理器缓存
cache.delete('seo_processor')
comment_cache_key = 'article_comments_{id}'.format(
id=instance.article.id)
cache.delete(comment_cache_key)
delete_sidebar_cache()
delete_view_cache('article_comments', [str(instance.article.pk)])
comment_cache_key = 'article_comments_{id}'.format(id=instance.article.id) # Zxy生成评论缓存键
cache.delete(comment_cache_key) # Zxy清理评论缓存
delete_sidebar_cache() # Zxy清理侧边栏缓存
delete_view_cache('article_comments', [str(instance.article.pk)]) # Zxy清理文章评论缓存
_thread.start_new_thread(send_comment_email, (instance,))
_thread.start_new_thread(send_comment_email, (instance,)) # Zxy异步发送评论邮件
if clearcache:
if clearcache: # Zxy清理缓存
cache.clear()
# Zxy定义用户登录和登出的回调函数
@receiver(user_logged_in)
@receiver(user_logged_out)
def user_auth_callback(sender, request, user, **kwargs):
if user and user.username:
logger.info(user)
delete_sidebar_cache()
# cache.clear()
if user and user.username: # Zxy检查用户是否登录
logger.info(user) # Zxy记录用户信息
delete_sidebar_cache() # Zxy清理侧边栏缓存
# cache.clear() # Zxy清理所有缓存暂时注释

@ -1,62 +1,74 @@
# Zxy导入Django的编码工具
from django.utils.encoding import force_str
# Zxy导入Elasticsearch DSL的查询构造器
from elasticsearch_dsl import Q
# Zxy导入Haystack的搜索后端模块
from haystack.backends import BaseEngine, BaseSearchBackend, BaseSearchQuery, log_query
# Zxy导入Haystack的表单模块
from haystack.forms import ModelSearchForm
# Zxy导入Haystack的搜索结果模型
from haystack.models import SearchResult
# Zxy导入Haystack的日志工具
from haystack.utils import log as logging
# Zxy导入项目中的Elasticsearch文档和管理器
from blog.documents import ArticleDocument, ArticleDocumentManager
# Zxy导入项目中的文章模型
from blog.models import Article
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy定义Elasticsearch搜索后端类
class ElasticSearchBackend(BaseSearchBackend):
# Zxy初始化方法
def __init__(self, connection_alias, **connection_options):
super(
ElasticSearchBackend,
self).__init__(
connection_alias,
**connection_options)
self.manager = ArticleDocumentManager()
self.include_spelling = True
super(ElasticSearchBackend, self).__init__(connection_alias, **connection_options)
self.manager = ArticleDocumentManager() # Zxy初始化文档管理器
self.include_spelling = True # Zxy启用拼写建议
# Zxy获取模型数据并转换为文档
def _get_models(self, iterable):
models = iterable if iterable and iterable[0] else Article.objects.all()
docs = self.manager.convert_to_doc(models)
models = iterable if iterable and iterable[0] else Article.objects.all() # Zxy获取模型数据
docs = self.manager.convert_to_doc(models) # Zxy转换为Elasticsearch文档
return docs
# Zxy创建索引并重建数据
def _create(self, models):
self.manager.create_index()
docs = self._get_models(models)
self.manager.rebuild(docs)
self.manager.create_index() # Zxy创建索引
docs = self._get_models(models) # Zxy获取文档
self.manager.rebuild(docs) # Zxy重建索引数据
# Zxy删除模型数据
def _delete(self, models):
for m in models:
m.delete()
m.delete() # Zxy删除模型实例
return True
# Zxy重建索引数据
def _rebuild(self, models):
models = models if models else Article.objects.all()
docs = self.manager.convert_to_doc(models)
self.manager.update_docs(docs)
models = models if models else Article.objects.all() # Zxy获取模型数据
docs = self.manager.convert_to_doc(models) # Zxy转换为文档
self.manager.update_docs(docs) # Zxy更新索引数据
# Zxy更新索引
def update(self, index, iterable, commit=True):
models = self._get_models(iterable) # Zxy获取文档
self.manager.update_docs(models) # Zxy更新索引
models = self._get_models(iterable)
self.manager.update_docs(models)
# Zxy删除文档
def remove(self, obj_or_string):
models = self._get_models([obj_or_string])
self._delete(models)
models = self._get_models([obj_or_string]) # Zxy获取文档
self._delete(models) # Zxy删除文档
# Zxy清空索引
def clear(self, models=None, commit=True):
self.remove(None)
self.remove(None) # Zxy删除所有文档
# Zxy获取拼写建议
@staticmethod
def get_suggestion(query: str) -> str:
"""获取推荐词, 如果没有找到添加原搜索词"""
"""获取推荐词,如果没有找到则返回原搜索词"""
search = ArticleDocument.search() \
.query("match", body=query) \
.suggest('suggest_search', query, term={'field': 'body'}) \
@ -64,80 +76,78 @@ class ElasticSearchBackend(BaseSearchBackend):
keywords = []
for suggest in search.suggest.suggest_search:
if suggest["options"]:
keywords.append(suggest["options"][0]["text"])
if suggest["options"]: # Zxy检查是否有建议选项
keywords.append(suggest["options"][0]["text"]) # Zxy添加建议词
else:
keywords.append(suggest["text"])
keywords.append(suggest["text"]) # Zxy添加原搜索词
return ' '.join(keywords)
return ' '.join(keywords) # Zxy返回拼写建议
# Zxy执行搜索查询
@log_query
def search(self, query_string, **kwargs):
logger.info('search query_string:' + query_string)
logger.info('search query_string:' + query_string) # Zxy记录搜索查询
start_offset = kwargs.get('start_offset')
end_offset = kwargs.get('end_offset')
start_offset = kwargs.get('start_offset') # Zxy获取起始偏移量
end_offset = kwargs.get('end_offset') # Zxy获取结束偏移量
# 推荐词搜索
# Zxy检查是否启用拼写建议
if getattr(self, "is_suggest", None):
suggestion = self.get_suggestion(query_string)
suggestion = self.get_suggestion(query_string) # Zxy获取拼写建议
else:
suggestion = query_string
suggestion = query_string # Zxy使用原搜索词
q = Q('bool',
should=[Q('match', body=suggestion), Q('match', title=suggestion)],
minimum_should_match="70%")
q = Q('bool', # Zxy构造布尔查询
should=[Q('match', body=suggestion), Q('match', title=suggestion)], # Zxy匹配标题或正文
minimum_should_match="70%") # Zxy至少匹配70%
search = ArticleDocument.search() \
.query('bool', filter=[q]) \
.filter('term', status='p') \
.filter('term', type='a') \
.source(False)[start_offset: end_offset]
.source(False)[start_offset: end_offset] # Zxy执行搜索
results = search.execute()
hits = results['hits'].total
raw_results = []
for raw_result in results['hits']['hits']:
app_label = 'blog'
model_name = 'Article'
additional_fields = {}
results = search.execute() # Zxy执行搜索查询
hits = results['hits'].total # Zxy获取总匹配数
raw_results = [] # Zxy初始化结果列表
result_class = SearchResult
for raw_result in results['hits']['hits']: # Zxy遍历搜索结果
app_label = 'blog' # Zxy应用标签
model_name = 'Article' # Zxy模型名称
additional_fields = {} # Zxy额外字段
result = result_class(
result_class = SearchResult # Zxy搜索结果类
result = result_class( # Zxy创建搜索结果对象
app_label,
model_name,
raw_result['_id'],
raw_result['_score'],
**additional_fields)
raw_results.append(result)
facets = {}
spelling_suggestion = None if query_string == suggestion else suggestion
**additional_fields
)
raw_results.append(result) # Zxy添加到结果列表
facets = {} # Zxy初始化分面信息
spelling_suggestion = None if query_string == suggestion else suggestion # Zxy拼写建议
return {
'results': raw_results,
'hits': hits,
'facets': facets,
'spelling_suggestion': spelling_suggestion,
'results': raw_results, # Zxy返回搜索结果
'hits': hits, # Zxy返回匹配数
'facets': facets, # Zxy返回分面信息
'spelling_suggestion': spelling_suggestion, # Zxy返回拼写建议
}
# Zxy定义Elasticsearch搜索查询类
class ElasticSearchQuery(BaseSearchQuery):
# Zxy转换日期时间格式
def _convert_datetime(self, date):
if hasattr(date, 'hour'):
return force_str(date.strftime('%Y%m%d%H%M%S'))
else:
return force_str(date.strftime('%Y%m%d000000'))
# Zxy清理用户输入
def clean(self, query_fragment):
"""
Provides a mechanism for sanitizing user input before presenting the
value to the backend.
Whoosh 1.X differs here in that you can no longer use a backslash
to escape reserved characters. Instead, the whole word should be
quoted.
"""
words = query_fragment.split()
cleaned_words = []
@ -154,30 +164,33 @@ class ElasticSearchQuery(BaseSearchQuery):
return ' '.join(cleaned_words)
# Zxy构建查询片段
def build_query_fragment(self, field, filter_type, value):
return value.query_string
# Zxy获取结果数量
def get_count(self):
results = self.get_results()
return len(results) if results else 0
# Zxy获取拼写建议
def get_spelling_suggestion(self, preferred_query=None):
return self._spelling_suggestion
# Zxy构建查询参数
def build_params(self, spelling_query=None):
kwargs = super(ElasticSearchQuery, self).build_params(spelling_query=spelling_query)
return kwargs
# Zxy定义Elasticsearch模型搜索表单
class ElasticSearchModelSearchForm(ModelSearchForm):
# Zxy执行搜索
def search(self):
# 是否建议搜索
self.searchqueryset.query.backend.is_suggest = self.data.get("is_suggest") != "no"
sqs = super().search()
self.searchqueryset.query.backend.is_suggest = self.data.get("is_suggest") != "no" # Zxy检查是否启用拼写建议
sqs = super().search() # Zxy调用父类搜索方法
return sqs
# Zxy定义Elasticsearch搜索引擎
class ElasticSearchEngine(BaseEngine):
backend = ElasticSearchBackend
query = ElasticSearchQuery
backend = ElasticSearchBackend # Zxy后端类
query = ElasticSearchQuery # Zxy查询类

@ -1,40 +1,54 @@
# Zxy导入Django的用户模型
from django.contrib.auth import get_user_model
# Zxy导入Django的Feed视图
from django.contrib.syndication.views import Feed
# Zxy导入Django的时区工具
from django.utils import timezone
# Zxy导入RSS 2.0 Feed生成器
from django.utils.feedgenerator import Rss201rev2Feed
# Zxy导入项目中的文章模型
from blog.models import Article
# Zxy导入Markdown工具
from djangoblog.utils import CommonMarkdown
# Zxy定义Django博客Feed
class DjangoBlogFeed(Feed):
feed_type = Rss201rev2Feed
feed_type = Rss201rev2Feed # Zxy使用RSS 2.0格式
description = '大巧无工,重剑无锋.'
title = "且听风吟 大巧无工,重剑无锋. "
link = "/feed/"
description = '大巧无工,重剑无锋.' # ZxyFeed描述
title = "且听风吟 大巧无工,重剑无锋." # ZxyFeed标题
link = "/feed/" # ZxyFeed链接
# Zxy获取作者名称
def author_name(self):
return get_user_model().objects.first().nickname
# Zxy获取作者链接
def author_link(self):
return get_user_model().objects.first().get_absolute_url()
# Zxy获取Feed项
def items(self):
return Article.objects.filter(type='a', status='p').order_by('-pub_time')[:5]
return Article.objects.filter(type='a', status='p').order_by('-pub_time')[:5] # Zxy获取最近5篇已发布的文章
# Zxy获取Feed项标题
def item_title(self, item):
return item.title
# Zxy获取Feed项描述
def item_description(self, item):
return CommonMarkdown.get_markdown(item.body)
return CommonMarkdown.get_markdown(item.body) # Zxy将文章内容转换为Markdown格式
# Zxy获取Feed版权信息
def feed_copyright(self):
now = timezone.now()
return "Copyright© {year} 且听风吟".format(year=now.year)
return "Copyright© {year} 且听风吟".format(year=now.year) # Zxy动态生成版权年份
# Zxy获取Feed项链接
def item_link(self, item):
return item.get_absolute_url()
# Zxy获取Feed项GUID
def item_guid(self, item):
return
return

@ -1,91 +1,88 @@
# Zxy导入Django的admin模块
from django.contrib import admin
# Zxy导入Django的LogEntry模型
from django.contrib.admin.models import DELETION
# Zxy导入Django的内容类型模型
from django.contrib.contenttypes.models import ContentType
# Zxy导入Django的URL工具
from django.urls import reverse, NoReverseMatch
# Zxy导入Django的编码工具
from django.utils.encoding import force_str
# Zxy导入Django的HTML工具
from django.utils.html import escape
# Zxy导入Django的安全字符串工具
from django.utils.safestring import mark_safe
# Zxy导入Django的翻译工具
from django.utils.translation import gettext_lazy as _
# Zxy定义LogEntryAdmin类
class LogEntryAdmin(admin.ModelAdmin):
list_filter = [
'content_type'
]
search_fields = [
'object_repr',
'change_message'
]
list_filter = ['content_type'] # Zxy按内容类型过滤
search_fields = ['object_repr', 'change_message'] # Zxy搜索字段
list_display_links = [
'action_time',
'get_change_message',
]
list_display = [
'action_time',
'user_link',
'content_type',
'object_link',
'get_change_message',
]
list_display_links = ['action_time', 'get_change_message'] # Zxy显示链接的字段
list_display = ['action_time', 'user_link', 'content_type', 'object_link', 'get_change_message'] # Zxy显示字段
# Zxy检查是否有添加权限
def has_add_permission(self, request):
return False
# Zxy检查是否有修改权限
def has_change_permission(self, request, obj=None):
return (
request.user.is_superuser or
request.user.has_perm('admin.change_logentry')
) and request.method != 'POST'
# Zxy检查是否有删除权限
def has_delete_permission(self, request, obj=None):
return False
# Zxy获取对象链接
def object_link(self, obj):
object_link = escape(obj.object_repr)
object_link = escape(obj.object_repr) # Zxy转义对象表示
content_type = obj.content_type
if obj.action_flag != DELETION and content_type is not None:
# try returning an actual link instead of object repr string
if obj.action_flag != DELETION and content_type is not None: # Zxy检查是否为删除操作
try:
url = reverse(
'admin:{}_{}_change'.format(content_type.app_label,
content_type.model),
url = reverse( # Zxy生成反向URL
'admin:{}_{}_change'.format(content_type.app_label, content_type.model),
args=[obj.object_id]
)
object_link = '<a href="{}">{}</a>'.format(url, object_link)
object_link = '<a href="{}">{}</a>'.format(url, object_link) # Zxy生成链接
except NoReverseMatch:
pass
return mark_safe(object_link)
return mark_safe(object_link) # Zxy标记为安全字符串
object_link.admin_order_field = 'object_repr'
object_link.short_description = _('object')
object_link.admin_order_field = 'object_repr' # Zxy排序字段
object_link.short_description = _('object') # Zxy字段描述
# Zxy获取用户链接
def user_link(self, obj):
content_type = ContentType.objects.get_for_model(type(obj.user))
user_link = escape(force_str(obj.user))
content_type = ContentType.objects.get_for_model(type(obj.user)) # Zxy获取用户的内容类型
user_link = escape(force_str(obj.user)) # Zxy转义用户表示
try:
# try returning an actual link instead of object repr string
url = reverse(
'admin:{}_{}_change'.format(content_type.app_label,
content_type.model),
url = reverse( # Zxy生成反向URL
'admin:{}_{}_change'.format(content_type.app_label, content_type.model),
args=[obj.user.pk]
)
user_link = '<a href="{}">{}</a>'.format(url, user_link)
user_link = '<a href="{}">{}</a>'.format(url, user_link) # Zxy生成链接
except NoReverseMatch:
pass
return mark_safe(user_link)
return mark_safe(user_link) # Zxy标记为安全字符串
user_link.admin_order_field = 'user'
user_link.short_description = _('user')
user_link.admin_order_field = 'user' # Zxy排序字段
user_link.short_description = _('user') # Zxy字段描述
# Zxy获取查询集
def get_queryset(self, request):
queryset = super(LogEntryAdmin, self).get_queryset(request)
return queryset.prefetch_related('content_type')
return queryset.prefetch_related('content_type') # Zxy预加载内容类型
# Zxy获取操作
def get_actions(self, request):
actions = super(LogEntryAdmin, self).get_actions(request)
if 'delete_selected' in actions:
if 'delete_selected' in actions: # Zxy移除删除操作
del actions['delete_selected']
return actions
return actions

@ -1,27 +1,33 @@
# Zxy导入日志模块
import logging
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy定义基础插件类
class BasePlugin:
# 插件元数据
PLUGIN_NAME = None
PLUGIN_DESCRIPTION = None
PLUGIN_VERSION = None
# Zxy插件元数据
PLUGIN_NAME = None # Zxy插件名称
PLUGIN_DESCRIPTION = None # Zxy插件描述
PLUGIN_VERSION = None # Zxy插件版本
# Zxy初始化插件
def __init__(self):
# Zxy检查插件元数据是否已定义
if not all([self.PLUGIN_NAME, self.PLUGIN_DESCRIPTION, self.PLUGIN_VERSION]):
raise ValueError("Plugin metadata (PLUGIN_NAME, PLUGIN_DESCRIPTION, PLUGIN_VERSION) must be defined.")
self.init_plugin()
self.register_hooks()
self.init_plugin() # Zxy调用初始化方法
self.register_hooks() # Zxy注册钩子
# Zxy插件初始化逻辑
def init_plugin(self):
"""
插件初始化逻辑
子类可以重写此方法来实现特定的初始化操作
"""
logger.info(f'{self.PLUGIN_NAME} initialized.')
logger.info(f'{self.PLUGIN_NAME} initialized.') # Zxy记录插件初始化日志
# Zxy注册插件钩子
def register_hooks(self):
"""
注册插件钩子
@ -29,13 +35,14 @@ class BasePlugin:
"""
pass
# Zxy获取插件信息
def get_plugin_info(self):
"""
获取插件信息
:return: 包含插件元数据的字典
"""
return {
'name': self.PLUGIN_NAME,
'description': self.PLUGIN_DESCRIPTION,
'version': self.PLUGIN_VERSION
}
'name': self.PLUGIN_NAME, # Zxy插件名称
'description': self.PLUGIN_DESCRIPTION, # Zxy插件描述
'version': self.PLUGIN_VERSION # Zxy插件版本
}

@ -1,7 +1,8 @@
ARTICLE_DETAIL_LOAD = 'article_detail_load'
ARTICLE_CREATE = 'article_create'
ARTICLE_UPDATE = 'article_update'
ARTICLE_DELETE = 'article_delete'
ARTICLE_CONTENT_HOOK_NAME = "the_content"
# Zxy定义文章相关的钩子常量
ARTICLE_DETAIL_LOAD = 'article_detail_load' # Zxy文章详情加载时触发的钩子
ARTICLE_CREATE = 'article_create' # Zxy文章创建时触发的钩子
ARTICLE_UPDATE = 'article_update' # Zxy文章更新时触发的钩子
ARTICLE_DELETE = 'article_delete' # Zxy文章删除时触发的钩子
# Zxy定义文章内容处理的钩子名称
ARTICLE_CONTENT_HOOK_NAME = "the_content" # Zxy文章内容处理的钩子名称

@ -1,44 +1,47 @@
# Zxy导入日志模块
import logging
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy定义全局钩子字典
_hooks = {}
# Zxy注册钩子回调
def register(hook_name: str, callback: callable):
"""
注册一个钩子回调
"""
if hook_name not in _hooks:
_hooks[hook_name] = []
_hooks[hook_name].append(callback)
logger.debug(f"Registered hook '{hook_name}' with callback '{callback.__name__}'")
if hook_name not in _hooks: # Zxy检查钩子是否已存在
_hooks[hook_name] = [] # Zxy初始化钩子列表
_hooks[hook_name].append(callback) # Zxy添加回调到钩子列表
logger.debug(f"Registered hook '{hook_name}' with callback '{callback.__name__}'") # Zxy记录注册日志
# Zxy执行Action Hook
def run_action(hook_name: str, *args, **kwargs):
"""
执行一个 Action Hook
它会按顺序执行所有注册到该钩子上的回调函数
"""
if hook_name in _hooks:
logger.debug(f"Running action hook '{hook_name}'")
for callback in _hooks[hook_name]:
if hook_name in _hooks: # Zxy检查钩子是否存在
logger.debug(f"Running action hook '{hook_name}'") # Zxy记录执行日志
for callback in _hooks[hook_name]: # Zxy遍历钩子回调
try:
callback(*args, **kwargs)
callback(*args, **kwargs) # Zxy执行回调
except Exception as e:
logger.error(f"Error running action hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True)
logger.error(f"Error running action hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True) # Zxy记录错误日志
# Zxy执行Filter Hook
def apply_filters(hook_name: str, value, *args, **kwargs):
"""
执行一个 Filter Hook
它会把 value 依次传递给所有注册的回调函数进行处理
"""
if hook_name in _hooks:
logger.debug(f"Applying filter hook '{hook_name}'")
for callback in _hooks[hook_name]:
if hook_name in _hooks: # Zxy检查钩子是否存在
logger.debug(f"Applying filter hook '{hook_name}'") # Zxy记录执行日志
for callback in _hooks[hook_name]: # Zxy遍历钩子回调
try:
value = callback(value, *args, **kwargs)
value = callback(value, *args, **kwargs) # Zxy调用回调处理值
except Exception as e:
logger.error(f"Error applying filter hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True)
return value
logger.error(f"Error applying filter hook '{hook_name}' callback '{callback.__name__}': {e}", exc_info=True) # Zxy记录错误日志
return value # Zxy返回处理后的值

@ -1,19 +1,24 @@
# Zxy导入os模块用于操作路径
import os
# Zxy导入日志模块
import logging
# Zxy导入Django的配置模块
from django.conf import settings
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy动态加载插件
def load_plugins():
"""
Dynamically loads and initializes plugins from the 'plugins' directory.
This function is intended to be called when the Django app registry is ready.
"""
for plugin_name in settings.ACTIVE_PLUGINS:
plugin_path = os.path.join(settings.PLUGINS_DIR, plugin_name)
if os.path.isdir(plugin_path) and os.path.exists(os.path.join(plugin_path, 'plugin.py')):
for plugin_name in settings.ACTIVE_PLUGINS: # Zxy遍历激活的插件
plugin_path = os.path.join(settings.PLUGINS_DIR, plugin_name) # Zxy获取插件路径
if os.path.isdir(plugin_path) and os.path.exists(os.path.join(plugin_path, 'plugin.py')): # Zxy检查插件目录和文件
try:
__import__(f'plugins.{plugin_name}.plugin')
logger.info(f"Successfully loaded plugin: {plugin_name}")
__import__(f'plugins.{plugin_name}.plugin') # Zxy动态导入插件模块
logger.info(f"Successfully loaded plugin: {plugin_name}") # Zxy记录加载成功日志
except ImportError as e:
logger.error(f"Failed to import plugin: {plugin_name}", exc_info=e)
logger.error(f"Failed to import plugin: {plugin_name}", exc_info=e) # Zxy记录加载失败日志

@ -16,12 +16,13 @@ from pathlib import Path
from django.utils.translation import gettext_lazy as _
# Zxy环境变量布尔值转换函数将环境变量转换为布尔值
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'.
# Zxy项目根目录获取项目的绝对路径
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
@ -30,20 +31,20 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# 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!
# Zxy调试模式从环境变量获取或默认为 True
DEBUG = env_to_bool('DJANGO_DEBUG', True)
# DEBUG = False
# Zxy测试模式检测检查是否运行测试
TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'
# ALLOWED_HOSTS = []
# Zxy允许的主机名允许访问的域名列表
ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com']
# django 4.0新增配置
# ZxyCSRF 可信来源:允许的 CSRF 来源
CSRF_TRUSTED_ORIGINS = ['http://example.com']
# Application definition
# Zxy应用程序定义定义项目中使用的 Django 应用程序
INSTALLED_APPS = [
# 'django.contrib.admin',
# 默认的 Django 应用程序
'django.contrib.admin.apps.SimpleAdminConfig',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -52,6 +53,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'django.contrib.sites',
'django.contrib.sitemaps',
# 第三方和自定义应用程序
'mdeditor',
'haystack',
'blog',
@ -63,7 +65,7 @@ INSTALLED_APPS = [
'compressor',
'djangoblog'
]
# Zxy中间件配置定义请求处理的中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
@ -80,9 +82,9 @@ MIDDLEWARE = [
'django.middleware.http.ConditionalGetMiddleware',
'blog.middleware.OnlineMiddleware'
]
# ZxyURL 配置:定义项目的 URL 配置文件
ROOT_URLCONF = 'djangoblog.urls'
# Zxy模板配置配置 Django 模板引擎
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
@ -99,29 +101,27 @@ TEMPLATES = [
},
},
]
# ZxyWSGI 应用程序:定义 WSGI 应用程序入口
WSGI_APPLICATION = 'djangoblog.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
# Zxy数据库配置配置数据库连接
DATABASES = {
'default': {
'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'},
}}
'NAME': 'djangoblog',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
# Zxy密码验证器配置密码验证规则
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@ -136,7 +136,7 @@ AUTH_PASSWORD_VALIDATORS = [
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Zxy语言和时区配置配置语言和时区
LANGUAGES = (
('en', _('English')),
('zh-hans', _('Simplified Chinese')),
@ -159,7 +159,7 @@ USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
# ZxyHaystack 搜索配置:配置 Haystack 搜索引擎
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine',
@ -171,12 +171,12 @@ HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# Allow user login with username and password
AUTHENTICATION_BACKENDS = [
'accounts.user_login_backend.EmailOrUsernameModelBackend']
# Zxy静态文件配置配置静态文件路径
STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic')
STATIC_URL = '/static/'
STATICFILES = os.path.join(BASE_DIR, 'static')
# Zxy用户模型配置定义自定义用户模型和登录 URL
AUTH_USER_MODEL = 'accounts.BlogUser'
LOGIN_URL = '/login/'
@ -193,6 +193,7 @@ PAGINATE_BY = 10
# http cache timeout
CACHE_CONTROL_MAX_AGE = 2592000
# cache setting
# Zxy缓存配置配置缓存后端
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
@ -208,7 +209,7 @@ if os.environ.get("DJANGO_REDIS_URL"):
'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}',
}
}
# Zxy站点 ID定义当前站点的 ID
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'
@ -232,7 +233,7 @@ WXADMIN = os.environ.get(
LOG_PATH = os.path.join(BASE_DIR, 'logs')
if not os.path.exists(LOG_PATH):
os.makedirs(LOG_PATH, exist_ok=True)
# Zxy日志配置配置日志记录
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
@ -293,7 +294,7 @@ LOGGING = {
}
}
}
# Zxy压缩配置配置静态文件压缩
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
@ -313,13 +314,13 @@ COMPRESS_CSS_FILTERS = [
COMPRESS_JS_FILTERS = [
'compressor.filters.jsmin.JSMinFilter'
]
# Zxy媒体文件配置配置媒体文件路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/media/'
X_FRAME_OPTIONS = 'SAMEORIGIN'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# ZxyElasticsearch 配置:配置 Elasticsearch 搜索引擎
if os.environ.get('DJANGO_ELASTICSEARCH_HOST'):
ELASTICSEARCH_DSL = {
'default': {
@ -332,7 +333,7 @@ if os.environ.get('DJANGO_ELASTICSEARCH_HOST'):
},
}
# Plugin System
# Zxy插件系统配置定义插件目录和激活的插件
PLUGINS_DIR = BASE_DIR / 'plugins'
ACTIVE_PLUGINS = [
'article_copyright',

@ -1,59 +1,70 @@
# Zxy导入 Django 的 Sitemap 模块和其他相关模块
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from blog.models import Article, Category, Tag
# Zxy定义静态页面的 Sitemap
class StaticViewSitemap(Sitemap):
priority = 0.5
changefreq = 'daily'
priority = 0.5 # Zxy设置优先级
changefreq = 'daily' # Zxy设置更新频率
def items(self):
# Zxy返回静态页面的 URL 名称
return ['blog:index', ]
def location(self, item):
# Zxy通过 URL 名称生成完整的 URL
return reverse(item)
# Zxy定义文章的 Sitemap
class ArticleSiteMap(Sitemap):
changefreq = "monthly"
priority = "0.6"
changefreq = "monthly" # Zxy文章更新频率为每月
priority = "0.6" # Zxy文章优先级
def items(self):
# Zxy返回所有已发布的文章
return Article.objects.filter(status='p')
def lastmod(self, obj):
# Zxy返回文章的最后修改时间
return obj.last_modify_time
# Zxy定义分类的 Sitemap
class CategorySiteMap(Sitemap):
changefreq = "Weekly"
priority = "0.6"
changefreq = "Weekly" # Zxy分类更新频率为每周
priority = "0.6" # Zxy分类优先级
def items(self):
# Zxy返回所有分类
return Category.objects.all()
def lastmod(self, obj):
# Zxy返回分类的最后修改时间
return obj.last_modify_time
# Zxy定义标签的 Sitemap
class TagSiteMap(Sitemap):
changefreq = "Weekly"
priority = "0.3"
changefreq = "Weekly" # Zxy标签更新频率为每周
priority = "0.3" # Zxy标签优先级
def items(self):
# Zxy返回所有标签
return Tag.objects.all()
def lastmod(self, obj):
# Zxy返回标签的最后修改时间
return obj.last_modify_time
# Zxy定义用户的 Sitemap
class UserSiteMap(Sitemap):
changefreq = "Weekly"
priority = "0.3"
changefreq = "Weekly" # Zxy用户更新频率为每周
priority = "0.3" # Zxy用户优先级
def items(self):
# Zxy返回所有用户的作者列表去重
return list(set(map(lambda x: x.author, Article.objects.all())))
def lastmod(self, obj):
return obj.date_joined
# Zxy返回用户的注册时间
return obj.date_joined

@ -1,21 +1,26 @@
# Zxy导入日志模块
import logging
# Zxy导入 requests 模块用于发送 HTTP 请求
import requests
from django.conf import settings
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy定义爬虫通知类
class SpiderNotify():
@staticmethod
def baidu_notify(urls):
# Zxy向百度站长平台发送 URL 提交请求
try:
data = '\n'.join(urls)
result = requests.post(settings.BAIDU_NOTIFY_URL, data=data)
logger.info(result.text)
data = '\n'.join(urls) # Zxy将 URL 列表拼接为字符串
result = requests.post(settings.BAIDU_NOTIFY_URL, data=data) # Zxy发送 POST 请求
logger.info(result.text) # Zxy记录响应内容
except Exception as e:
logger.error(e)
logger.error(e) # Zxy记录异常信息
@staticmethod
def notify(url):
SpiderNotify.baidu_notify(url)
# Zxy调用百度通知方法
SpiderNotify.baidu_notify(url)

@ -1,16 +1,21 @@
# Zxy导入 Django 的测试模块
from django.test import TestCase
# Zxy导入项目中的工具函数
from djangoblog.utils import *
# Zxy定义测试类
class DjangoBlogTest(TestCase):
def setUp(self):
# Zxy测试初始化方法暂无内容
pass
def test_utils(self):
md5 = get_sha256('test')
self.assertIsNotNone(md5)
c = CommonMarkdown.get_markdown('''
# Zxy测试工具函数
md5 = get_sha256('test') # Zxy测试 SHA256 函数
self.assertIsNotNone(md5) # Zxy断言返回值不为空
c = CommonMarkdown.get_markdown(''' # Zxy测试 Markdown 转换
# Title1
```python
@ -23,10 +28,11 @@ class DjangoBlogTest(TestCase):
''')
self.assertIsNotNone(c)
self.assertIsNotNone(c) # Zxy断言返回值不为空
d = {
'd': 'key1',
'd2': 'key2'
}
data = parse_dict_to_url(d)
self.assertIsNotNone(data)
data = parse_dict_to_url(d) # Zxy测试字典转 URL 函数
self.assertIsNotNone(data) # Zxy断言返回值不为空

@ -1,3 +1,4 @@
# Zxy定义项目的 URL 配置
"""djangoblog URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
@ -27,8 +28,8 @@ from djangoblog.elasticsearch_backend import ElasticSearchModelSearchForm
from djangoblog.feeds import DjangoBlogFeed
from djangoblog.sitemap import ArticleSiteMap, CategorySiteMap, StaticViewSitemap, TagSiteMap, UserSiteMap
# Zxy定义站点地图
sitemaps = {
'blog': ArticleSiteMap,
'Category': CategorySiteMap,
'Tag': TagSiteMap,
@ -36,29 +37,32 @@ sitemaps = {
'static': StaticViewSitemap
}
# Zxy定义 404、500 和 403 错误页面的视图
handler404 = 'blog.views.page_not_found_view'
handler500 = 'blog.views.server_error_view'
handle403 = 'blog.views.permission_denied_view'
# Zxy定义 URL 模式
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
path('i18n/', include('django.conf.urls.i18n')), # Zxy国际化语言切换
]
urlpatterns += i18n_patterns(
re_path(r'^admin/', admin_site.urls),
re_path(r'', include('blog.urls', namespace='blog')),
re_path(r'mdeditor/', include('mdeditor.urls')),
re_path(r'', include('comments.urls', namespace='comment')),
re_path(r'', include('accounts.urls', namespace='account')),
re_path(r'', include('oauth.urls', namespace='oauth')),
re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps},
re_path(r'^admin/', admin_site.urls), # Zxy自定义 Admin 站点
re_path(r'', include('blog.urls', namespace='blog')), # Zxy博客应用的 URL
re_path(r'mdeditor/', include('mdeditor.urls')), # Zxy Markdown 编辑器的 URL
re_path(r'', include('comments.urls', namespace='comment')), # Zxy评论应用的 URL
re_path(r'', include('accounts.urls', namespace='account')), # Zxy用户账户的 URL
re_path(r'', include('oauth.urls', namespace='oauth')), # Zxy OAuth 应用的 URL
re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, # Zxy站点地图
name='django.contrib.sitemaps.views.sitemap'),
re_path(r'^feed/$', DjangoBlogFeed()),
re_path(r'^rss/$', DjangoBlogFeed()),
re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm),
re_path(r'^feed/$', DjangoBlogFeed()), # Zxy RSS 订阅
re_path(r'^rss/$', DjangoBlogFeed()), # Zxy RSS 订阅
re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm), # Zxy搜索功能
name='search'),
re_path(r'', include('servermanager.urls', namespace='servermanager')),
re_path(r'', include('owntracks.urls', namespace='owntracks'))
, prefix_default_language=False) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
re_path(r'', include('servermanager.urls', namespace='servermanager')), # Zxy服务器管理应用的 URL
re_path(r'', include('owntracks.urls', namespace='owntracks')), # Zxy位置跟踪应用的 URL
prefix_default_language=False
) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # Zxy静态文件的 URL
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.MEDIA_URL, # Zxy媒体文件的 URL
document_root=settings.MEDIA_ROOT)

@ -1,7 +1,7 @@
#!/usr/bin/env python
# encoding: utf-8
# Zxy导入日志模块
import logging
import os
import random
@ -17,20 +17,21 @@ from django.contrib.sites.models import Site
from django.core.cache import cache
from django.templatetags.static import static
# Zxy获取日志记录器
logger = logging.getLogger(__name__)
# Zxy获取文章和评论的最大 ID
def get_max_articleid_commentid():
from blog.models import Article
from comments.models import Comment
return (Article.objects.latest().pk, Comment.objects.latest().pk)
# Zxy计算字符串的 SHA256 值
def get_sha256(str):
m = sha256(str.encode('utf-8'))
return m.hexdigest()
# Zxy缓存装饰器用于缓存函数的返回值
def cache_decorator(expiration=3 * 60):
def wrapper(func):
def news(*args, **kwargs):
@ -41,41 +42,27 @@ def cache_decorator(expiration=3 * 60):
key = None
if not key:
unique_str = repr((func, args, kwargs))
m = sha256(unique_str.encode('utf-8'))
key = m.hexdigest()
value = cache.get(key)
if value is not None:
# logger.info('cache_decorator get cache:%s key:%s' % (func.__name__, key))
if str(value) == '__default_cache_value__':
return None
else:
return value
else:
logger.debug(
'cache_decorator set cache:%s key:%s' %
(func.__name__, key))
logger.debug('cache_decorator set cache:%s key:%s' % (func.__name__, key))
value = func(*args, **kwargs)
if value is None:
cache.set(key, '__default_cache_value__', expiration)
else:
cache.set(key, value, expiration)
return value
return news
return wrapper
# Zxy刷新视图缓存
def expire_view_cache(path, servername, serverport, key_prefix=None):
'''
刷新视图缓存
:param path:url路径
:param servername:host
:param serverport:端口
:param key_prefix:前缀
:return:是否成功
'''
from django.http import HttpRequest
from django.utils.cache import get_cache_key
@ -91,24 +78,17 @@ def expire_view_cache(path, servername, serverport, key_prefix=None):
return True
return False
# Zxy获取当前站点
@cache_decorator()
def get_current_site():
site = Site.objects.get_current()
return site
# Zxy定义 CommonMarkdown 类,用于处理 Markdown 转换
class CommonMarkdown:
@staticmethod
def _convert_markdown(value):
md = markdown.Markdown(
extensions=[
'extra',
'codehilite',
'toc',
'tables',
]
)
md = markdown.Markdown(extensions=['extra', 'codehilite', 'toc', 'tables'])
body = md.convert(value)
toc = md.toc
return body, toc
@ -123,28 +103,22 @@ class CommonMarkdown:
body, toc = CommonMarkdown._convert_markdown(value)
return body
# Zxy发送邮件
def send_email(emailto, title, content):
from djangoblog.blog_signals import send_email_signal
send_email_signal.send(
send_email.__class__,
emailto=emailto,
title=title,
content=content)
send_email_signal.send(send_email.__class__, emailto=emailto, title=title, content=content)
# Zxy生成随机验证码
def generate_code() -> str:
"""生成随机数验证码"""
return ''.join(random.sample(string.digits, 6))
# Zxy将字典转换为 URL 参数
def parse_dict_to_url(dict):
from urllib.parse import quote
url = '&'.join(['{}={}'.format(quote(k, safe='/'), quote(v, safe='/'))
for k, v in dict.items()])
url = '&'.join(['{}={}'.format(quote(k, safe='/'), quote(v, safe='/')) for k, v in dict.items()])
return url
# Zxy获取博客设置
def get_blog_setting():
value = cache.get('get_blog_setting')
if value:
@ -172,22 +146,15 @@ def get_blog_setting():
cache.set('get_blog_setting', value)
return value
# Zxy保存用户头像
def save_user_avatar(url):
'''
保存用户头像
:param url:头像url
:return: 本地路径
'''
logger.info(url)
try:
basedir = os.path.join(settings.STATICFILES, 'avatar')
rsp = requests.get(url, timeout=2)
if rsp.status_code == 200:
if not os.path.exists(basedir):
os.makedirs(basedir)
image_extensions = ['.jpg', '.png', 'jpeg', '.gif']
isimage = len([i for i in image_extensions if url.endswith(i)]) > 0
ext = os.path.splitext(url)[1] if isimage else '.jpg'
@ -200,7 +167,7 @@ def save_user_avatar(url):
logger.error(e)
return static('blog/img/avatar.png')
# Zxy删除侧边栏缓存
def delete_sidebar_cache():
from blog.models import LinkShowType
keys = ["sidebar" + x for x in LinkShowType.values]
@ -208,13 +175,13 @@ def delete_sidebar_cache():
logger.info('delete sidebar key:' + k)
cache.delete(k)
# Zxy删除视图缓存
def delete_view_cache(prefix, keys):
from django.core.cache.utils import make_template_fragment_key
key = make_template_fragment_key(prefix, keys)
cache.delete(key)
# Zxy获取资源 URL
def get_resource_url():
if settings.STATIC_URL:
return settings.STATIC_URL
@ -222,11 +189,10 @@ def get_resource_url():
site = get_current_site()
return 'http://' + site.domain + '/static/'
ALLOWED_TAGS = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1',
'h2', 'p']
# Zxy定义允许的 HTML 标签和属性
ALLOWED_TAGS = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1', 'h2', 'p']
ALLOWED_ATTRIBUTES = {'a': ['href', 'title'], 'abbr': ['title'], 'acronym': ['title']}
# Zxy清理 HTML 内容
def sanitize_html(html):
return bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES)
return bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES)

File diff suppressed because it is too large Load Diff

@ -7,10 +7,14 @@ For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
"""
# Zxy导入os模块用于操作环境变量
import os
# Zxy从Django中导入get_wsgi_application函数用于获取WSGI应用
from django.core.wsgi import get_wsgi_application
# Zxy设置环境变量DJANGO_SETTINGS_MODULE指定Django项目的配置文件
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangoblog.settings")
application = get_wsgi_application()
# Zxy获取WSGI应用实例用于部署
application = get_wsgi_application()
Loading…
Cancel
Save