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'))