diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..10b731c
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
diff --git a/.idea/DjangoBlog-master.iml b/.idea/DjangoBlog-master.iml
new file mode 100644
index 0000000..d2ab4f7
--- /dev/null
+++ b/.idea/DjangoBlog-master.iml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..4c5155d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..5494c00
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..8306744
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/blog/models.py b/src/blog/models.py
index 083788b..5a179a5 100644
--- a/src/blog/models.py
+++ b/src/blog/models.py
@@ -16,27 +16,28 @@ from djangoblog.utils import get_current_site
logger = logging.getLogger(__name__)
-
+#zhq: 链接显示类型选择类 - 定义链接在不同页面的显示方式
class LinkShowType(models.TextChoices):
- I = ('i', _('index'))
- L = ('l', _('list'))
- P = ('p', _('post'))
- A = ('a', _('all'))
- S = ('s', _('slide'))
-
+ I = ('i', _('index'))#zhq: 首页显示
+ L = ('l', _('list'))#zhq: 列表页显示
+ P = ('p', _('post'))#zhq: 文章页显示
+ A = ('a', _('all'))#zhq: 所有页面显示
+ S = ('s', _('slide'))#zhq: 幻灯片显示
+#zhq: 基础模型抽象类 - 所有模型的基类,包含公共字段和方法
class BaseModel(models.Model):
id = models.AutoField(primary_key=True)
creation_time = models.DateTimeField(_('creation time'), default=now)
last_modify_time = models.DateTimeField(_('modify time'), default=now)
- def save(self, *args, **kwargs):
+ def save(self, *args, **kwargs):#zhq: 特殊处理文章浏览量的更新,避免触发其他字段的保存逻辑
is_update_views = isinstance(
self,
Article) and 'update_fields' in kwargs and kwargs['update_fields'] == ['views']
if is_update_views:
Article.objects.filter(pk=self.pk).update(views=self.views)
else:
+ # zhq: 自动生成slug字段,用于SEO友好的URL
if 'slug' in self.__dict__:
slug = getattr(
self, 'title') if 'title' in self.__dict__ else getattr(
@@ -45,6 +46,7 @@ class BaseModel(models.Model):
super().save(*args, **kwargs)
def get_full_url(self):
+ # zhq: 获取对象的完整URL地址
site = get_current_site().domain
url = "https://{site}{path}".format(site=site,
path=self.get_absolute_url())
@@ -55,9 +57,10 @@ class BaseModel(models.Model):
@abstractmethod
def get_absolute_url(self):
+ # zhq: 抽象方法,子类必须实现获取绝对URL的方法
pass
-
+#zhq: 文章模型 - 博客的核心内容模型
class Article(BaseModel):
"""文章"""
STATUS_CHOICES = (
@@ -112,7 +115,7 @@ class Article(BaseModel):
return self.title
class Meta:
- ordering = ['-article_order', '-pub_time']
+ ordering = ['-article_order', '-pub_time']#zhq: 按排序和发布时间降序排列
verbose_name = _('article')
verbose_name_plural = verbose_name
get_latest_by = 'id'
@@ -127,6 +130,7 @@ class Article(BaseModel):
@cache_decorator(60 * 60 * 10)
def get_category_tree(self):
+ # zhq: 获取文章所属分类的完整树形结构
tree = self.category.get_category_tree()
names = list(map(lambda c: (c.name, c.get_absolute_url()), tree))
@@ -136,10 +140,12 @@ class Article(BaseModel):
super().save(*args, **kwargs)
def viewed(self):
+ # zhq: 增加文章浏览量
self.views += 1
self.save(update_fields=['views'])
def comment_list(self):
+ # zhq: 获取文章的评论列表,带缓存功能
cache_key = 'article_comments_{id}'.format(id=self.id)
value = cache.get(cache_key)
if value:
@@ -152,6 +158,7 @@ class Article(BaseModel):
return comments
def get_admin_url(self):
+ # zhq: 获取文章在Admin后台的编辑链接
info = (self._meta.app_label, self._meta.model_name)
return reverse('admin:%s_%s_change' % info, args=(self.pk,))
@@ -176,7 +183,7 @@ class Article(BaseModel):
return match.group(1)
return ""
-
+#zhq: 分类模型 - 支持多级分类结构
class Category(BaseModel):
"""文章分类"""
name = models.CharField(_('category name'), max_length=30, unique=True)
@@ -185,7 +192,7 @@ class Category(BaseModel):
verbose_name=_('parent category'),
blank=True,
null=True,
- on_delete=models.CASCADE)
+ on_delete=models.CASCADE) #zhq: 自关联,支持多级分类
slug = models.SlugField(default='no-slug', max_length=60, blank=True)
index = models.IntegerField(default=0, verbose_name=_('index'))
@@ -239,7 +246,7 @@ class Category(BaseModel):
parse(self)
return categorys
-
+#zhq: 标签模型 - 简单的标签管理
class Tag(BaseModel):
"""文章标签"""
name = models.CharField(_('tag name'), max_length=30, unique=True)
@@ -253,6 +260,7 @@ class Tag(BaseModel):
@cache_decorator(60 * 60 * 10)
def get_article_count(self):
+ # zhq: 获取该标签下的文章数量
return Article.objects.filter(tags__name=self.name).distinct().count()
class Meta:
@@ -260,32 +268,32 @@ class Tag(BaseModel):
verbose_name = _('tag')
verbose_name_plural = verbose_name
-
+#zhq: 友情链接模型
class Links(models.Model):
"""友情链接"""
name = models.CharField(_('link name'), max_length=30, unique=True)
link = models.URLField(_('link'))
- sequence = models.IntegerField(_('order'), unique=True)
+ sequence = models.IntegerField(_('order'), unique=True) #zhq: 链接显示顺序
is_enable = models.BooleanField(
_('is show'), default=True, blank=False, null=False)
show_type = models.CharField(
_('show type'),
max_length=1,
choices=LinkShowType.choices,
- default=LinkShowType.I)
+ default=LinkShowType.I) #zhq: 链接显示类型
creation_time = models.DateTimeField(_('creation time'), default=now)
last_mod_time = models.DateTimeField(_('modify time'), default=now)
class Meta:
- ordering = ['sequence']
+ ordering = ['sequence'] #zhq: 按顺序排列
verbose_name = _('link')
verbose_name_plural = verbose_name
def __str__(self):
return self.name
-
+#zhq: 侧边栏模型 - 支持自定义HTML内容
class SideBar(models.Model):
"""侧边栏,可以展示一些html内容"""
name = models.CharField(_('title'), max_length=100)
@@ -303,7 +311,7 @@ class SideBar(models.Model):
def __str__(self):
return self.name
-
+#zhq: 博客设置模型 - 单例模式,存储全局配置
class BlogSettings(models.Model):
"""blog的配置"""
site_name = models.CharField(
@@ -326,11 +334,11 @@ class BlogSettings(models.Model):
null=False,
blank=False,
default='')
- article_sub_length = models.IntegerField(_('article sub length'), default=300)
- sidebar_article_count = models.IntegerField(_('sidebar article count'), default=10)
- sidebar_comment_count = models.IntegerField(_('sidebar comment count'), default=5)
- article_comment_count = models.IntegerField(_('article comment count'), default=5)
- show_google_adsense = models.BooleanField(_('show adsense'), default=False)
+ article_sub_length = models.IntegerField(_('article sub length'), default=300) #zhq: 文章摘要长度
+ sidebar_article_count = models.IntegerField(_('sidebar article count'), default=10) #zhq: 侧边栏文章数量
+ sidebar_comment_count = models.IntegerField(_('sidebar comment count'), default=5) #zhq: 侧边栏评论数量
+ article_comment_count = models.IntegerField(_('article comment count'), default=5) #zhq: 文章页评论数量
+ show_google_adsense = models.BooleanField(_('show adsense'), default=False) #zhq:是否显示Google广告
google_adsense_codes = models.TextField(
_('adsense code'), max_length=2000, null=True, blank=True, default='')
open_site_comment = models.BooleanField(_('open site comment'), default=True)
@@ -341,13 +349,13 @@ class BlogSettings(models.Model):
max_length=2000,
null=True,
blank=True,
- default='')
+ default='') #zhq: ICP备案号
analytics_code = models.TextField(
"网站统计代码",
max_length=1000,
null=False,
blank=False,
- default='')
+ default='') #zhq: 网站统计代码
show_gongan_code = models.BooleanField(
'是否显示公安备案号', default=False, null=False)
gongan_beiancode = models.TextField(
@@ -357,7 +365,7 @@ class BlogSettings(models.Model):
blank=True,
default='')
comment_need_review = models.BooleanField(
- '评论是否需要审核', default=False, null=False)
+ '评论是否需要审核', default=False, null=False) #zhq: 评论审核开关
class Meta:
verbose_name = _('Website configuration')
@@ -367,6 +375,7 @@ class BlogSettings(models.Model):
return self.site_name
def clean(self):
+ # zhq: 确保配置表只有一条记录(单例模式)
if BlogSettings.objects.exclude(id=self.id).count():
raise ValidationError(_('There can only be one configuration'))