diff --git a/1 b/1 deleted file mode 100644 index 56a6051..0000000 --- a/1 +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index a9f77b5..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# django - diff --git a/doc/TECH数据模型设计.docx b/doc/TECH数据模型设计.docx new file mode 100644 index 0000000..57b3318 Binary files /dev/null and b/doc/TECH数据模型设计.docx differ diff --git a/doc/代码注释.css b/doc/代码注释.css new file mode 100644 index 0000000..df33a32 --- /dev/null +++ b/doc/代码注释.css @@ -0,0 +1,521 @@ +/* ========================================================================== + 面包屑导航样式 + ========================================================================== */ + +.breadcrumb +div { + display: inline; + font-size: 13px; + margin-left: -3px; +} + +/* ========================================================================== + 回到顶部按钮样式 + ========================================================================== */ + +/* 回到顶部按钮容器定位 */ +#wp-auto-top { + position: fixed; + top: 45%; + right: 50%; + display: block; + margin-right: -540px; + z-index: 9999; +} + +/* 回到顶部按钮通用样式 */ +#wp-auto-top-top, #wp-auto-top-comment, #wp-auto-top-bottom { + background: url(https://www.lylinux.org/wp-content/plugins/wp-auto-top/img/1.png) no-repeat; + position: relative; + cursor: pointer; + height: 25px; + width: 29px; + margin: 10px 0 0; +} + +/* 评论按钮特定样式 */ +#wp-auto-top-comment { + background-position: left -30px; + height: 32px; +} + +/* 底部按钮特定样式 */ +#wp-auto-top-bottom { + background-position: left -68px; +} + +/* 按钮悬停效果 */ +#wp-auto-top-comment:hover { + background-position: right -30px; +} + +#wp-auto-top-top:hover { + background-position: right 0; +} + +#wp-auto-top-bottom:hover { + background-position: right -68px; +} + +/* ========================================================================== + 登录小工具样式 + ========================================================================== */ + +.widget-login { + margin-top: 15px !important; +} + +/* ========================================================================== + 评论区域样式 + ========================================================================== */ + +/* 评论区域顶部间距 */ +#comments { + margin-top: 20px; +} + +/* 隐藏pingback列表容器 */ +#pinglist-container { + display: none; +} + +/* 评论标签页样式 */ +.comment-tabs { + margin-bottom: 20px; + font-size: 15px; + border-bottom: 2px solid #e5e5e5; +} + +.comment-tabs li { + float: left; + margin-bottom: -2px; +} + +.comment-tabs li a { + display: block; + padding: 0 10px 10px; + font-weight: 600; + color: #aaa; + border-bottom: 2px solid #e5e5e5; +} + +.comment-tabs li a:hover { + color: #444; + border-color: #ccc; +} + +.comment-tabs li span { + margin-left: 8px; + padding: 0 6px; + border-radius: 4px; + background-color: #e5e5e5; +} + +.comment-tabs li i { + margin-right: 6px; +} + +.comment-tabs li.active a { + color: #e8554e; + border-bottom-color: #e8554e; +} + +/* 评论列表样式 */ +.commentlist, .pinglist { + margin-bottom: 20px; +} + +.commentlist li, .pinglist li { + padding-left: 60px; + font-size: 14px; + line-height: 22px; + font-weight: 400; +} + +.commentlist .comment-body, .pinglist li { + position: relative; + padding-bottom: 20px; + clear: both; + word-break: break-all; +} + +.commentlist .comment-author, +.commentlist .comment-meta, +.commentlist .comment-awaiting-moderation { + float: left; + display: block; + font-size: 13px; + line-height: 22px; +} + +.commentlist .comment-author { + margin-right: 6px; +} + +.commentlist .fn, .pinglist .ping-link { + color: #444; + font-size: 13px; + font-style: normal; + font-weight: 600; +} + +.commentlist .says { + display: none; +} + +.commentlist .avatar { + position: absolute; + left: -60px; + top: 0; + width: 48px; + height: 48px; + border-radius: 100%; +} + +.commentlist .comment-meta:before, .pinglist .ping-meta:before { + vertical-align: 4%; + margin-right: 3px; + font-size: 10px; + font-family: FontAwesome; + color: #ccc; +} + +.commentlist .comment-meta a, .pinglist .ping-meta { + color: #aaa; +} + +.commentlist .reply { + font-size: 13px; + line-height: 16px; +} + +.commentlist .reply a, +.commentlist .comment-reply-chain { + color: #aaa; +} + +.commentlist .reply a:hover, +.commentlist .comment-reply-chain:hover { + color: #444; +} + +.comment-awaiting-moderation { + color: #e8554e; + font-style: normal; +} + +/* pingback 列表样式 */ +.pinglist li { + padding-left: 0; +} + +/* 评论文本样式 */ +.commentlist .comment-body p { + margin-bottom: 8px; + color: #777; + clear: both; +} + +.commentlist .comment-body strong { + font-weight: 600; +} + +.commentlist .comment-body ol li { + margin-left: 2em; + padding: 0; + list-style: decimal; +} + +.commentlist .comment-body ul li { + margin-left: 2em; + padding: 0; + list-style: square; +} + +/* 文章作者和管理员评论样式 */ +.commentlist li.bypostauthor > .comment-body:after, +.commentlist li.comment-author-admin > .comment-body:after { + display: block; + position: absolute; + content: "\f040"; + width: 12px; + line-height: 12px; + font-style: normal; + font-family: FontAwesome; + text-align: center; + color: #fff; + background-color: #e8554e; +} + +.commentlist li.comment-author-admin > .comment-body:after { + content: "\f005"; /* 管理员使用星形图标 */ +} + +.commentlist li.bypostauthor > .comment-body:after, +.commentlist li.comment-author-admin > .comment-body:after { + padding: 3px; + top: 32px; + left: -28px; + font-size: 12px; + border-radius: 100%; +} + +.commentlist li li.bypostauthor > .comment-body:after, +.commentlist li li.comment-author-admin > .comment-body:after { + padding: 2px; + top: 22px; + left: -26px; + font-size: 10px; + border-radius: 100%; +} + +/* 子评论样式 */ +.commentlist li ul { +} + +.commentlist li li { + margin: 0; + padding-left: 48px; +} + +.commentlist li li .avatar { + top: 0; + left: -48px; + width: 36px; + height: 36px; +} + +.commentlist li li .comment-meta { + left: 70px; +} + +/* 评论导航样式 */ +.comments-nav { + margin-bottom: 20px; +} + +.comments-nav a { + font-weight: 600; +} + +.comments-nav .nav-previous { + float: left; +} + +.comments-nav .nav-next { + float: right; +} + +/* 评论表单样式 */ +.logged-in-as, +.comment-notes, +.form-allowed-tags { + display: none; +} + +/* 设置评论容器相对定位 */ +#respond { + position: relative; +} + +/* 回复标题的默认下边距 */ +#reply-title { + margin-bottom: 20px; +} + +/* 针对列表项中的回复标题进行特殊处理:隐藏并重置尺寸 */ +li #reply-title { + margin: 0 !important; + padding: 0; + height: 0; + font-size: 0; + border-top: 0; +} + +/* 取消回复链接的基本样式设置 */ +#cancel-comment-reply-link { + float: right; + bottom: 26px; + right: 20px; + font-size: 12px; + color: #999; +} + +/* 取消回复链接悬停时的颜色变化 */ +#cancel-comment-reply-link:hover { + color: #777; +} + +/* 评论表单整体样式 */ +#commentform { + margin-bottom: 20px; + padding: 10px 20px 20px; + border-radius: 4px; + background-color: #e5e5e5; +} + +/* 表单作者字段左浮动占宽48% */ +#commentform p.comment-form-author { + float: left; + width: 48%; +} + +/* 表单邮箱字段右浮动占宽48% */ +#commentform p.comment-form-email { + float: right; + width: 48%; +} + +/* URL 和评论正文字段清除浮动并独占一行 */ +#commentform p.comment-form-url, +#commentform p.comment-form-comment { + clear: both; +} + +/* 表单标签统一显示为块级元素,并设置上下内边距与字体加粗 */ +#commentform label { + display: block; + padding: 6px 0; + font-weight: 600; +} + +/* 输入框和文本域最大宽度限制为父容器100%,且默认撑满 */ +#commentform input[type="text"], +#commentform textarea { + max-width: 100%; + width: 100%; +} + +/* 文本域高度固定为100像素 */ +#commentform textarea { + height: 100px; +} + +/* 提交按钮段落上外边距调整 */ +#commentform p.form-submit { + margin-top: 10px; +} + +/* 登录状态下回复标题保持标准间距 */ +.logged-in #reply-title { + margin-bottom: 20px; +} + +/* 登录状态下的评论正文字段增加顶部间距 */ +.logged-in #commentform p.comment-form-comment { + margin-top: 10px; +} + +/* 登录状态下评论正文标签隐藏 */ +.logged-in #commentform p.comment-form-comment label { + display: none; +} + +/* 统一标题类(包括回复标题)的基础样式 */ +.heading, +#reply-title { + margin-bottom: 1em; + font-size: 18px; + font-weight: 600; + text-transform: uppercase; + color: #222; +} + +/* 标题图标样式设置 */ +.heading i { + margin-right: 6px; + font-size: 22px; +} + +/* 清除浮动伪类 before */ +.group:before { + content: ""; + display: table; +} + +/* 清除浮动伪类 after */ +.group:after { + content: ""; + display: table; + clear: both; +} + +/* 取消评论按钮基础样式重置 */ +.cancel-comment { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + +/* 返回顶部火箭图标的初始位置及基本属性 */ +#rocket { + position: fixed; + right: 50px; + bottom: 50px; + display: block; + visibility: hidden; + width: 26px; + height: 48px; + background: url("data:image/png;base64,...") no-repeat 50% 0; + cursor: pointer; + -webkit-transition: all 0s; + transition: all 0s; +} + +/* 火箭图标鼠标悬停时背景图片偏移以切换状态 */ +#rocket:hover { + background-position: 50% -62px; +} + +/* 显示火箭图标 */ +#rocket.show { + visibility: visible; + opacity: 1; +} + +/* 触发动画时火箭图标的状态更新与动画绑定 */ +#rocket.move { + background-position: 50% -62px; + -webkit-animation: toTop .8s ease-in; + animation: toTop .8s ease-in; + animation-fill-mode: forwards; + -webkit-animation-fill-mode: forwards; +} + +/* Markdown提示文字样式设置 */ +.comment-markdown { + float: right; + font-size: small; +} + +/* 面包屑导航容器样式 */ +.breadcrumb { + margin-bottom: 20px; + list-style: none; + border-radius: 4px; +} + +/* 面包屑导航项横向排列 */ +.breadcrumb > li { + display: inline-block; +} + +/* 面包屑导航项之间的分隔符 */ +.breadcrumb > li + li:before { + color: #ccc; + content: "/\00a0"; +} + +/* 当前激活的面包屑导航项颜色 */ +.breadcrumb > .active { + color: #777; +} + +/* 分割线样式(当前被注释掉) */ +.break_line { + height: 1px; + border: none; + /*border-top: 1px dashed #f5d6d6;*/ +} \ No newline at end of file diff --git a/sitemap.py b/sitemap.py new file mode 100644 index 0000000..ca48dba --- /dev/null +++ b/sitemap.py @@ -0,0 +1,132 @@ +""" +DjangoBlog 站点地图配置模块 +功能:为搜索引擎提供网站结构地图,支持文章、分类、标签等内容的自动索引 +""" + +from django.contrib.sitemaps import Sitemap +from django.urls import reverse + +from blog.models import Article, Category, Tag + + +class StaticViewSitemap(Sitemap): + """ + 静态页面站点地图 + 用于生成固定页面的站点地图,如首页等 + """ + # 优先级:0.5(中等优先级,首页等重要页面可以设为1.0) + priority = 0.5 + # 更新频率:每天检查 + changefreq = 'daily' + + def items(self): + """ + 返回包含在站点地图中的静态页面名称 + 这些名称需要与 urls.py 中的 URL 名称对应 + """ + return ['blog:index', ] # 博客首页 + + def location(self, item): + """ + 根据页面名称生成完整的 URL 地址 + """ + return reverse(item) + + +class ArticleSiteMap(Sitemap): + """ + 文章站点地图 + 自动生成所有已发布文章的站点地图 + """ + # 更新频率:每月检查(文章内容相对稳定) + changefreq = "monthly" + # 优先级:0.6(文章是核心内容,优先级较高) + priority = "0.6" + + def items(self): + """ + 返回所有已发布的文章对象 + status='p' 表示已发布状态 + """ + return Article.objects.filter(status='p') + + def lastmod(self, obj): + """ + 返回文章的最后修改时间 + 帮助搜索引擎了解内容更新情况 + """ + return obj.last_modify_time + + +class CategorySiteMap(Sitemap): + """ + 分类站点地图 + 生成文章分类页面的站点地图 + """ + # 更新频率:每周检查(分类结构相对稳定) + changefreq = "Weekly" + # 优先级:0.6(分类页面重要程度较高) + priority = "0.6" + + def items(self): + """ + 返回所有分类对象 + """ + return Category.objects.all() + + def lastmod(self, obj): + """ + 返回分类的最后修改时间 + 当分类下的文章更新时,分类页面也需要更新 + """ + return obj.last_modify_time + + +class TagSiteMap(Sitemap): + """ + 标签站点地图 + 生成标签页面的站点地图 + """ + # 更新频率:每周检查 + changefreq = "Weekly" + # 优先级:0.3(标签页面重要性相对较低) + priority = "0.3" + + def items(self): + """ + 返回所有标签对象 + """ + return Tag.objects.all() + + def lastmod(self, obj): + """ + 返回标签的最后修改时间 + 当标签关联的文章更新时,标签页面也需要更新 + """ + return obj.last_modify_time + + +class UserSiteMap(Sitemap): + """ + 用户站点地图 + 生成用户主页的站点地图 + """ + # 更新频率:每周检查 + changefreq = "Weekly" + # 优先级:0.3(用户页面重要性相对较低) + priority = "0.3" + + def items(self): + """ + 返回所有发表过文章的用户(作者) + 使用 set 去重,确保每个用户只出现一次 + """ + return list(set(map(lambda x: x.author, Article.objects.all()))) + + def lastmod(self, obj): + """ + 返回用户的注册时间 + 这里使用用户注册时间作为最后修改时间 + 实际可以根据用户最后活动时间优化 + """ + return obj.date_joined \ No newline at end of file diff --git a/src/DjangoBlog-master/accounts/admin.py b/src/DjangoBlog-master/accounts/admin.py index 32e483c..110a797 100644 --- a/src/DjangoBlog-master/accounts/admin.py +++ b/src/DjangoBlog-master/accounts/admin.py @@ -1,59 +1,107 @@ from django import forms -from django.contrib.auth.admin import UserAdmin -from django.contrib.auth.forms import UserChangeForm -from django.contrib.auth.forms import UsernameField -from django.utils.translation import gettext_lazy as _ +from django.contrib.auth.admin import UserAdmin # Django 自带的用户管理后台基类 +from django.contrib.auth.forms import UserChangeForm # Django 默认的用户信息修改表单 +from django.contrib.auth.forms import UsernameField # Django 用于用户名字段的专用表单字段 +from django.utils.translation import gettext_lazy as _ # 用于支持多语言翻译的辅助函数 -# Register your models here. +# 从当前 app 的 models 导入自定义的用户模型 BlogUser from .models import BlogUser +# ====================== +# 自定义用户创建表单(用于后台添加用户时使用) +# ====================== class BlogUserCreationForm(forms.ModelForm): - password1 = forms.CharField(label=_('password'), widget=forms.PasswordInput) - password2 = forms.CharField(label=_('Enter password again'), widget=forms.PasswordInput) + # 添加两个密码字段,用于用户注册时输入和确认密码 + password1 = forms.CharField( + label=_('password'), # 字段显示名称(可翻译),这里是“password” + widget=forms.PasswordInput # 使用密码输入框,输入内容会被隐藏 + ) + password2 = forms.CharField( + label=_('Enter password again'), # 确认密码的标签 + widget=forms.PasswordInput # 同样是密码输入框 + ) class Meta: - model = BlogUser - fields = ('email',) + model = BlogUser # 指定该表单关联的模型是 BlogUser + fields = ('email',) # 在创建用户时,只显示 email 字段(可以从后台选择的字段) def clean_password2(self): - # Check that the two password entries match + """ + 校验两次输入的密码是否一致 + """ + # 从 cleaned_data 中获取用户输入的两个密码 password1 = self.cleaned_data.get("password1") password2 = self.cleaned_data.get("password2") + + # 如果两个密码都有值,但它们不相等,则抛出验证错误 if password1 and password2 and password1 != password2: - raise forms.ValidationError(_("passwords do not match")) + raise forms.ValidationError(_("passwords do not match")) # 提示“密码不匹配” + + # 验证通过,返回 password2(通常返回确认密码字段的值) return password2 def save(self, commit=True): - # Save the provided password in hashed format + """ + 保存用户对象,并对密码进行哈希处理 + """ + # 调用父类的 save 方法,但不立即提交到数据库(commit=False) user = super().save(commit=False) + + # 对用户输入的密码(password1)进行哈希处理,并设置到 user 对象上 user.set_password(self.cleaned_data["password1"]) + if commit: + # 如果 commit=True(默认),则保存到数据库 + # 同时,给用户添加一个来源标识 source = 'adminsite',表示是通过后台添加的 user.source = 'adminsite' user.save() + + # 返回保存后的用户对象 return user +# ====================== +# 自定义用户修改表单(用于后台编辑用户信息时使用) +# ====================== class BlogUserChangeForm(UserChangeForm): class Meta: - model = BlogUser - fields = '__all__' + model = BlogUser # 指定关联的模型是 BlogUser + fields = '__all__' # 表单中包含模型的所有字段 + # 指定 username 字段使用 Django 提供的 UsernameField,它对用户名有特殊处理(如唯一性等) field_classes = {'username': UsernameField} - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + """ + 初始化方法,这里暂时没有额外逻辑,只是调用了父类的初始化 + """ + super().__init__(*args, **kwargs) +# ====================== +# 自定义用户管理后台类(用于在 Django Admin 中管理 BlogUser 模型) +# ====================== class BlogUserAdmin(UserAdmin): + # 指定用户修改时使用的表单类(编辑用户信息时) form = BlogUserChangeForm + + # 指定用户创建时使用的表单类(添加新用户时) add_form = BlogUserCreationForm + + # 定义在用户列表页显示哪些字段 list_display = ( - 'id', - 'nickname', - 'username', - 'email', - 'last_login', - 'date_joined', - 'source') + 'id', # 用户 ID + 'nickname', # 昵称(假设你的 BlogUser 模型中有这个字段) + 'username', # 用户名 + 'email', # 邮箱 + 'last_login', # 上次登录时间 + 'date_joined', # 注册时间 + 'source' # 用户来源(比如 adminsite 表示后台添加) + ) + + # 定义哪些字段可以作为链接,点击后可以进入编辑页面 + # 这里 id 和 username 都可以作为链接 list_display_links = ('id', 'username') - ordering = ('-id',) + + # 定义默认排序方式,这里是按照 id 降序(最新的用户在前面) + ordering = ('-id',) \ No newline at end of file diff --git a/src/DjangoBlog-master/comments/admin.py b/src/DjangoBlog-master/comments/admin.py index a814f3f..d412b89 100644 --- a/src/DjangoBlog-master/comments/admin.py +++ b/src/DjangoBlog-master/comments/admin.py @@ -1,47 +1,49 @@ -from django.contrib import admin -from django.urls import reverse -from django.utils.html import format_html -from django.utils.translation import gettext_lazy as _ +from django.contrib import admin# 导入Django admin相关模块,用于自定义后台管理 +from django.urls import reverse# 导入reverse函数,用于生成URL反向解析 +from django.utils.html import format_html# 导入format_html,用于安全生成HTML内容(防止XSS攻击) +from django.utils.translation import gettext_lazy as _# 导入gettext_lazy,用于国际化翻译(惰性加载,优化性能) -def disable_commentstatus(modeladmin, request, queryset): - queryset.update(is_enable=False) +def disable_commentstatus(modeladmin, request, queryset):# 自定义批量操作:禁用评论状态 + queryset.update(is_enable=False)# 将选中的评论记录批量更新is_enable字段为False(禁用) -def enable_commentstatus(modeladmin, request, queryset): - queryset.update(is_enable=True) +def enable_commentstatus(modeladmin, request, queryset):# 自定义批量操作:启用评论状态 + queryset.update(is_enable=True) # 将选中的评论记录批量更新is_enable字段为True(启用) -disable_commentstatus.short_description = _('Disable comments') +disable_commentstatus.short_description = _('Disable comments')# 为批量操作设置显示名称(支持国际化) enable_commentstatus.short_description = _('Enable comments') - +# 自定义评论模型的Admin管理类,控制后台评论的展示和操作 class CommentAdmin(admin.ModelAdmin): - list_per_page = 20 - list_display = ( + list_per_page = 20# 每页显示20条评论记录 + list_display = (# 列表页展示的字段(自定义字段需在类中定义对应方法) 'id', 'body', 'link_to_userinfo', 'link_to_article', 'is_enable', 'creation_time') - list_display_links = ('id', 'body', 'is_enable') - list_filter = ('is_enable',) - exclude = ('creation_time', 'last_modify_time') - actions = [disable_commentstatus, enable_commentstatus] - - def link_to_userinfo(self, obj): - info = (obj.author._meta.app_label, obj.author._meta.model_name) - link = reverse('admin:%s_%s_change' % info, args=(obj.author.id,)) - return format_html( + list_display_links = ('id', 'body', 'is_enable')# 列表页中可点击跳转编辑页的字段 + list_filter = ('is_enable',)# 右侧过滤条件(按是否启用筛选) + exclude = ('creation_time', 'last_modify_time')# 编辑页排除的字段(创建时间和最后修改时间通常自动生成,不允许手动编辑) + actions = [disable_commentstatus, enable_commentstatus]# 注册批量操作(将上面定义的两个函数加入到后台操作中) + + def link_to_userinfo(self, obj):# 自定义字段:生成关联用户的后台编辑链接 + info = (obj.author._meta.app_label, obj.author._meta.model_name)# 获取用户模型的app标签和模型名称(用于生成admin URL) + # obj.author表示评论关联的用户对象 + link = reverse('admin:%s_%s_change' % info, args=(obj.author.id,))# 反向解析生成用户模型的编辑页URL(格式:admin:app_label_model_name_change) + return format_html( # 生成HTML链接,显示用户昵称(若无昵称则显示邮箱) u'%s' % (link, obj.author.nickname if obj.author.nickname else obj.author.email)) - def link_to_article(self, obj): - info = (obj.article._meta.app_label, obj.article._meta.model_name) - link = reverse('admin:%s_%s_change' % info, args=(obj.article.id,)) - return format_html( + def link_to_article(self, obj):# 自定义字段:生成关联文章的后台编辑链接 + info = (obj.article._meta.app_label, obj.article._meta.model_name)# 获取文章模型的app标签和模型名称 + # obj.article表示评论关联的文章对象 + link = reverse('admin:%s_%s_change' % info, args=(obj.article.id,))# 反向解析生成文章模型的编辑页URL + return format_html(# 生成HTML链接,显示文章标题 u'%s' % (link, obj.article.title)) - - link_to_userinfo.short_description = _('User') - link_to_article.short_description = _('Article') + # 自定义字段的显示名称(支持国际化) + link_to_userinfo.short_description = _('User')# 显示为"用户" + link_to_article.short_description = _('Article')# 显示为"文章" diff --git a/src/DjangoBlog-master/deploy/entrypoint.sh b/src/DjangoBlog-master/deploy/entrypoint.sh index 2fb6491..c8e2ea0 100644 --- a/src/DjangoBlog-master/deploy/entrypoint.sh +++ b/src/DjangoBlog-master/deploy/entrypoint.sh @@ -1,31 +1,50 @@ #!/usr/bin/env bash +# 指定脚本解释器为bash + +# 定义应用名称为djangoblog NAME="djangoblog" +# 定义Django项目根目录路径 DJANGODIR=/code/djangoblog +# 定义运行应用的用户 USER=root +# 定义运行应用的用户组 GROUP=root +# 定义Gunicorn工作进程数量 NUM_WORKERS=1 +# 定义Django的WSGI模块路径 DJANGO_WSGI_MODULE=djangoblog.wsgi +# 输出启动信息,显示当前启动的应用名称和执行用户 echo "Starting $NAME as `whoami`" +# 进入Django项目根目录 cd $DJANGODIR +# 将项目目录添加到Python路径中,确保Python能正确导入项目模块 export PYTHONPATH=$DJANGODIR:$PYTHONPATH +# 执行Django项目初始化命令序列,若任何一步失败则退出脚本 +# 1. 生成数据库迁移文件 python manage.py makemigrations && \ + # 2. 应用数据库迁移 python manage.py migrate && \ + # 3. 收集静态文件(无交互模式) python manage.py collectstatic --noinput && \ + # 4. 强制压缩静态文件(通常用于CSS/JS压缩) python manage.py compress --force && \ + # 5. 构建搜索索引(如果项目使用了全文搜索功能) python manage.py build_index && \ + # 6. 编译翻译文件(用于国际化支持) python manage.py compilemessages || exit 1 +# 启动Gunicorn作为WSGI服务器,替换当前进程(exec命令特性) exec gunicorn ${DJANGO_WSGI_MODULE}:application \ ---name $NAME \ ---workers $NUM_WORKERS \ ---user=$USER --group=$GROUP \ ---bind 0.0.0.0:8000 \ ---log-level=debug \ ---log-file=- \ ---worker-class gevent \ ---threads 4 +--name $NAME \ # 指定应用名称 +--workers $NUM_WORKERS \ # 指定工作进程数量 +--user=$USER --group=$GROUP \ # 指定运行的用户和用户组 +--bind 0.0.0.0:8000 \ # 绑定监听地址和端口(0.0.0.0表示允许所有网络访问) +--log-level=debug \ # 设置日志级别为debug +--log-file=- \ # 日志输出到标准输出(-表示stdout) +--worker-class gevent \ # 使用gevent工作类(支持异步IO,提高并发性能) +--threads 4 # 每个工作进程的线程数量 \ No newline at end of file diff --git a/src/DjangoBlog-master/djangoblog/feeds.py b/src/DjangoBlog-master/djangoblog/feeds.py index 8c4e851..0ca207c 100644 --- a/src/DjangoBlog-master/djangoblog/feeds.py +++ b/src/DjangoBlog-master/djangoblog/feeds.py @@ -6,7 +6,7 @@ from django.utils.feedgenerator import Rss201rev2Feed from blog.models import Article from djangoblog.utils import CommonMarkdown - +/*注释*/ class DjangoBlogFeed(Feed): feed_type = Rss201rev2Feed diff --git a/src/DjangoBlog-master/templates/share_layout/base_account.html b/src/DjangoBlog-master/templates/share_layout/base_account.html index c00d842..fc8bf8d 100644 --- a/src/DjangoBlog-master/templates/share_layout/base_account.html +++ b/src/DjangoBlog-master/templates/share_layout/base_account.html @@ -1,34 +1,47 @@
+ {% load static %} - + + +