@ -14,29 +14,41 @@ from uuslug import slugify
from djangoblog . utils import cache_decorator , cache
from djangoblog . utils import get_current_site
logger = logging . getLogger ( __name__ )
logger = logging . getLogger ( __name__ ) # 创建日志记录器
class LinkShowType ( models . TextChoices ) :
I = ( ' i ' , _ ( ' index ' ) )
L = ( ' l ' , _ ( ' list ' ) )
P = ( ' p ' , _ ( ' post ' ) )
A = ( ' a ' , _ ( ' all ' ) )
S = ( ' s ' , _ ( ' slide ' ) )
"""
链接显示类型枚举类
"""
I = ( ' i ' , _ ( ' index ' ) ) # 首页
L = ( ' l ' , _ ( ' list ' ) ) # 列表页
P = ( ' p ' , _ ( ' post ' ) ) # 文章页面
A = ( ' a ' , _ ( ' all ' ) ) # 全站
S = ( ' s ' , _ ( ' slide ' ) ) # 幻灯片
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 ) :
"""
重写保存方法 , 处理slug生成和视图计数更新
"""
# 判断是否是仅更新浏览量的操作
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 :
# 如果有slug字段, 自动生成slug
if ' slug ' in self . __dict__ :
slug = getattr (
self , ' title ' ) if ' title ' in self . __dict__ else getattr (
@ -45,35 +57,42 @@ class BaseModel(models.Model):
super ( ) . save ( * args , * * kwargs )
def get_full_url ( self ) :
"""
获取完整的URL地址
"""
site = get_current_site ( ) . domain
url = " https:// {site} {path} " . format ( site = site ,
path = self . get_absolute_url ( ) )
return url
class Meta :
abstract = True
abstract = True # 声明为抽象类
@abstractmethod
def get_absolute_url ( self ) :
"""
抽象方法 , 子类必须实现获取绝对URL的方法
"""
pass
class Article ( BaseModel ) :
""" 文章 """
""" 文章 模型 """
STATUS_CHOICES = (
( ' d ' , _ ( ' Draft ' ) ) ,
( ' p ' , _ ( ' Published ' ) ) ,
( ' d ' , _ ( ' Draft ' ) ) , # 草稿
( ' p ' , _ ( ' Published ' ) ) , # 已发布
)
COMMENT_STATUS = (
( ' o ' , _ ( ' Open ' ) ) ,
( ' c ' , _ ( ' Close ' ) ) ,
( ' o ' , _ ( ' Open ' ) ) , # 开启评论
( ' c ' , _ ( ' Close ' ) ) , # 关闭评论
)
TYPE = (
( ' a ' , _ ( ' Article ' ) ) ,
( ' p ' , _ ( ' Page ' ) ) ,
( ' a ' , _ ( ' Article ' ) ) , # 文章
( ' p ' , _ ( ' Page ' ) ) , # 页面
)
title = models . CharField ( _ ( ' title ' ) , max_length = 200 , unique = True )
body = MDTextField ( _ ( ' body ' ) )
body = MDTextField ( _ ( ' body ' ) ) # 使用Markdown编辑器字段
pub_time = models . DateTimeField (
_ ( ' publish time ' ) , blank = False , null = False , default = now )
status = models . CharField (
@ -106,18 +125,24 @@ class Article(BaseModel):
tags = models . ManyToManyField ( ' Tag ' , verbose_name = _ ( ' tag ' ) , blank = True )
def body_to_string ( self ) :
"""
将文章正文转换为字符串
"""
return self . body
def __str__ ( self ) :
return self . title
class Meta :
ordering = [ ' -article_order ' , ' -pub_time ' ]
ordering = [ ' -article_order ' , ' -pub_time ' ] # 按排序和发布时间降序排列
verbose_name = _ ( ' article ' )
verbose_name_plural = verbose_name
get_latest_by = ' id '
def get_absolute_url ( self ) :
"""
获取文章绝对URL
"""
return reverse ( ' blog:detailbyid ' , kwargs = {
' article_id ' : self . id ,
' year ' : self . creation_time . year ,
@ -127,19 +152,31 @@ class Article(BaseModel):
@cache_decorator ( 60 * 60 * 10 )
def get_category_tree ( self ) :
"""
获取分类树结构
"""
tree = self . category . get_category_tree ( )
names = list ( map ( lambda c : ( c . name , c . get_absolute_url ( ) ) , tree ) )
return names
def save ( self , * args , * * kwargs ) :
"""
保存文章
"""
super ( ) . save ( * args , * * kwargs )
def viewed ( self ) :
"""
增加文章浏览量
"""
self . views + = 1
self . save ( update_fields = [ ' views ' ] )
def comment_list ( self ) :
"""
获取文章评论列表 ( 带缓存 )
"""
cache_key = ' article_comments_ {id} ' . format ( id = self . id )
value = cache . get ( cache_key )
if value :
@ -152,24 +189,33 @@ class Article(BaseModel):
return comments
def get_admin_url ( self ) :
"""
获取管理后台的文章编辑URL
"""
info = ( self . _meta . app_label , self . _meta . model_name )
return reverse ( ' admin: %s _ %s _change ' % info , args = ( self . pk , ) )
@cache_decorator ( expiration = 60 * 100 )
def next_article ( self ) :
"""
获取下一篇已发布的文章
"""
# 下一篇
return Article . objects . filter (
id__gt = self . id , status = ' p ' ) . order_by ( ' id ' ) . first ( )
@cache_decorator ( expiration = 60 * 100 )
def prev_article ( self ) :
"""
获取上一篇已发布的文章
"""
# 前一篇
return Article . objects . filter ( id__lt = self . id , status = ' p ' ) . first ( )
def get_first_image_url ( self ) :
"""
Get the first image url from article . body .
: return :
从文章正文中获取第一张图片的URL
: return : 图片URL或空字符串
"""
match = re . search ( r ' ! \ [.*? \ ] \ ((.+?) \ ) ' , self . body )
if match :
@ -178,7 +224,7 @@ class Article(BaseModel):
class Category ( BaseModel ) :
""" 文章分类 """
""" 文章分类 模型 """
name = models . CharField ( _ ( ' category name ' ) , max_length = 30 , unique = True )
parent_category = models . ForeignKey (
' self ' ,
@ -190,11 +236,14 @@ class Category(BaseModel):
index = models . IntegerField ( default = 0 , verbose_name = _ ( ' index ' ) )
class Meta :
ordering = [ ' -index ' ]
ordering = [ ' -index ' ] # 按索引降序排列
verbose_name = _ ( ' category ' )
verbose_name_plural = verbose_name
def get_absolute_url ( self ) :
"""
获取分类绝对URL
"""
return reverse (
' blog:category_detail ' , kwargs = {
' category_name ' : self . slug } )
@ -205,8 +254,8 @@ class Category(BaseModel):
@cache_decorator ( 60 * 60 * 10 )
def get_category_tree ( self ) :
"""
递归获得分类目录的父级
: return :
递归获得分类目录的父级 分类树
: return : 分类列表
"""
categorys = [ ]
@ -221,8 +270,8 @@ class Category(BaseModel):
@cache_decorator ( 60 * 60 * 10 )
def get_sub_categorys ( self ) :
"""
获得当前分类目录所有子 集
: return :
获得当前分类目录所有子 分类
: return : 子分类列表
"""
categorys = [ ]
all_categorys = Category . objects . all ( )
@ -241,7 +290,7 @@ class Category(BaseModel):
class Tag ( BaseModel ) :
""" 文章标签 """
""" 文章标签 模型 """
name = models . CharField ( _ ( ' tag name ' ) , max_length = 30 , unique = True )
slug = models . SlugField ( default = ' no-slug ' , max_length = 60 , blank = True )
@ -249,20 +298,26 @@ class Tag(BaseModel):
return self . name
def get_absolute_url ( self ) :
"""
获取标签绝对URL
"""
return reverse ( ' blog:tag_detail ' , kwargs = { ' tag_name ' : self . slug } )
@cache_decorator ( 60 * 60 * 10 )
def get_article_count ( self ) :
"""
获取该标签下的文章数量
"""
return Article . objects . filter ( tags__name = self . name ) . distinct ( ) . count ( )
class Meta :
ordering = [ ' name ' ]
ordering = [ ' name ' ] # 按名称升序排列
verbose_name = _ ( ' tag ' )
verbose_name_plural = verbose_name
class Links ( models . Model ) :
""" 友情链接 """
""" 友情链接 模型 """
name = models . CharField ( _ ( ' link name ' ) , max_length = 30 , unique = True )
link = models . URLField ( _ ( ' link ' ) )
@ -278,7 +333,7 @@ class Links(models.Model):
last_mod_time = models . DateTimeField ( _ ( ' modify time ' ) , default = now )
class Meta :
ordering = [ ' sequence ' ]
ordering = [ ' sequence ' ] # 按顺序排列
verbose_name = _ ( ' link ' )
verbose_name_plural = verbose_name
@ -287,7 +342,7 @@ class Links(models.Model):
class SideBar ( models . Model ) :
""" 侧边栏 ,可以展示一些html内容"""
""" 侧边栏 模型 ,可以展示一些html内容"""
name = models . CharField ( _ ( ' title ' ) , max_length = 100 )
content = models . TextField ( _ ( ' content ' ) )
sequence = models . IntegerField ( _ ( ' order ' ) , unique = True )
@ -296,7 +351,7 @@ class SideBar(models.Model):
last_mod_time = models . DateTimeField ( _ ( ' modify time ' ) , default = now )
class Meta :
ordering = [ ' sequence ' ]
ordering = [ ' sequence ' ] # 按顺序排列
verbose_name = _ ( ' sidebar ' )
verbose_name_plural = verbose_name
@ -305,7 +360,7 @@ class SideBar(models.Model):
class BlogSettings ( models . Model ) :
""" blog的配置 """
""" 博客配置模型 """
site_name = models . CharField (
_ ( ' site name ' ) ,
max_length = 200 ,
@ -367,10 +422,631 @@ class BlogSettings(models.Model):
return self . site_name
def clean ( self ) :
"""
验证模型数据 , 确保只存在一个配置实例
"""
if BlogSettings . objects . exclude ( id = self . id ) . count ( ) :
raise ValidationError ( _ ( ' There can only be one configuration ' ) )
def save ( self , * args , * * kwargs ) :
"""
保存配置并清除缓存
"""
super ( ) . save ( * args , * * kwargs )
from djangoblog . utils import cache
cache . clear ( )
import logging
import re
from abc import abstractmethod
from django . conf import settings
from django . core . exceptions import ValidationError
from django . db import models
from django . urls import reverse
from django . utils . timezone import now
from django . utils . translation import gettext_lazy as _
from mdeditor . fields import MDTextField
from uuslug import slugify
from djangoblog . utils import cache_decorator , cache
from djangoblog . utils import get_current_site
logger = logging . getLogger ( __name__ )
class LinkShowType ( models . TextChoices ) :
"""
链接显示类型枚举类
I : 首页显示
L : 列表页显示
P : 文章页显示
A : 所有页面显示
S : 幻灯片显示
"""
I = ( ' i ' , _ ( ' index ' ) )
L = ( ' l ' , _ ( ' list ' ) )
P = ( ' p ' , _ ( ' post ' ) )
A = ( ' a ' , _ ( ' all ' ) )
S = ( ' s ' , _ ( ' slide ' ) )
class BaseModel ( models . Model ) :
"""
基础模型类
提供所有模型共有的字段和方法 ,
包含主键 、 创建时间和最后修改时间字段
Attributes :
id ( AutoField ) : 主键字段
creation_time ( DateTimeField ) : 创建时间
last_modify_time ( DateTimeField ) : 最后修改时间
"""
id = models . AutoField (
primary_key = True ,
help_text = ' 主键ID ' )
creation_time = models . DateTimeField (
_ ( ' creation time ' ) ,
default = now ,
help_text = ' 记录创建时间 ' )
last_modify_time = models . DateTimeField (
_ ( ' modify time ' ) ,
default = now ,
help_text = ' 记录最后修改时间 ' )
def save ( self , * args , * * kwargs ) :
"""
重写保存方法
如果是更新文章浏览量 , 则只更新浏览量字段
否则 , 处理slug字段并调用父类保存方法
"""
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 :
if ' slug ' in self . __dict__ :
slug = getattr (
self , ' title ' ) if ' title ' in self . __dict__ else getattr (
self , ' name ' )
setattr ( self , ' slug ' , slugify ( slug ) )
super ( ) . save ( * args , * * kwargs )
def get_full_url ( self ) :
"""
获取完整URL地址
: return : 完整的URL地址 , 包含域名
"""
site = get_current_site ( ) . domain
url = " https:// {site} {path} " . format ( site = site ,
path = self . get_absolute_url ( ) )
return url
class Meta :
abstract = True
@abstractmethod
def get_absolute_url ( self ) :
"""
抽象方法 , 子类必须实现
返回模型对象的绝对URL路径
"""
pass
class Article ( BaseModel ) :
""" 文章 """
STATUS_CHOICES = (
( ' d ' , _ ( ' Draft ' ) ) ,
( ' p ' , _ ( ' Published ' ) ) ,
)
COMMENT_STATUS = (
( ' o ' , _ ( ' Open ' ) ) ,
( ' c ' , _ ( ' Close ' ) ) ,
)
TYPE = (
( ' a ' , _ ( ' Article ' ) ) ,
( ' p ' , _ ( ' Page ' ) ) ,
)
title = models . CharField (
_ ( ' title ' ) ,
max_length = 200 ,
unique = True ,
help_text = ' 文章标题,必须唯一 ' )
body = MDTextField (
_ ( ' body ' ) ,
help_text = ' 文章正文内容, 支持Markdown语法 ' )
pub_time = models . DateTimeField (
_ ( ' publish time ' ) ,
blank = False ,
null = False ,
default = now ,
help_text = ' 文章发布时间 ' )
status = models . CharField (
_ ( ' status ' ) ,
max_length = 1 ,
choices = STATUS_CHOICES ,
default = ' p ' ,
help_text = ' 文章状态:草稿或已发布 ' )
comment_status = models . CharField (
_ ( ' comment status ' ) ,
max_length = 1 ,
choices = COMMENT_STATUS ,
default = ' o ' ,
help_text = ' 评论状态:开放或关闭 ' )
type = models . CharField (
_ ( ' type ' ) ,
max_length = 1 ,
choices = TYPE ,
default = ' a ' ,
help_text = ' 文章类型:普通文章或页面 ' )
views = models . PositiveIntegerField (
_ ( ' views ' ) ,
default = 0 ,
help_text = ' 文章浏览量 ' )
author = models . ForeignKey (
settings . AUTH_USER_MODEL ,
verbose_name = _ ( ' author ' ) ,
blank = False ,
null = False ,
on_delete = models . CASCADE ,
help_text = ' 文章作者 ' )
article_order = models . IntegerField (
_ ( ' order ' ) ,
blank = False ,
null = False ,
default = 0 ,
help_text = ' 文章排序 ' )
show_toc = models . BooleanField (
_ ( ' show toc ' ) ,
blank = False ,
null = False ,
default = False ,
help_text = ' 是否显示目录 ' )
category = models . ForeignKey (
' Category ' ,
verbose_name = _ ( ' category ' ) ,
on_delete = models . CASCADE ,
blank = False ,
null = False ,
help_text = ' 文章分类 ' )
tags = models . ManyToManyField (
' Tag ' ,
verbose_name = _ ( ' tag ' ) ,
blank = True ,
help_text = ' 文章标签 ' )
def body_to_string ( self ) :
"""
将文章内容转换为字符串
: return : 文章内容字符串
"""
return self . body
def __str__ ( self ) :
return self . title
class Meta :
ordering = [ ' -article_order ' , ' -pub_time ' ]
verbose_name = _ ( ' article ' )
verbose_name_plural = verbose_name
get_latest_by = ' id '
def get_absolute_url ( self ) :
"""
获取文章详情页的URL
: return : 文章详情页URL
"""
return reverse ( ' blog:detailbyid ' , kwargs = {
' article_id ' : self . id ,
' year ' : self . creation_time . year ,
' month ' : self . creation_time . month ,
' day ' : self . creation_time . day
} )
@cache_decorator ( 60 * 60 * 10 )
def get_category_tree ( self ) :
"""
获取分类目录树
: return : 分类目录树列表
"""
tree = self . category . get_category_tree ( )
names = list ( map ( lambda c : ( c . name , c . get_absolute_url ( ) ) , tree ) )
return names
def save ( self , * args , * * kwargs ) :
"""
重写保存方法 , 调用父类保存方法
"""
super ( ) . save ( * args , * * kwargs )
def viewed ( self ) :
"""
增加文章浏览量
"""
self . views + = 1
self . save ( update_fields = [ ' views ' ] )
def comment_list ( self ) :
"""
获取文章的评论列表
使用缓存机制提高性能
: return : 评论列表
"""
cache_key = ' article_comments_ {id} ' . format ( id = self . id )
value = cache . get ( cache_key )
if value :
logger . info ( ' get article comments: {id} ' . format ( id = self . id ) )
return value
else :
comments = self . comment_set . filter ( is_enable = True ) . order_by ( ' -id ' )
cache . set ( cache_key , comments , 60 * 100 )
logger . info ( ' set article comments: {id} ' . format ( id = self . id ) )
return comments
def get_admin_url ( self ) :
"""
获取文章在管理后台的编辑URL
: return : 管理后台编辑URL
"""
info = ( self . _meta . app_label , self . _meta . model_name )
return reverse ( ' admin: %s _ %s _change ' % info , args = ( self . pk , ) )
@cache_decorator ( expiration = 60 * 100 )
def next_article ( self ) :
"""
获取下一篇文章
: return : 下一篇文章对象
"""
# 下一篇
return Article . objects . filter (
id__gt = self . id , status = ' p ' ) . order_by ( ' id ' ) . first ( )
@cache_decorator ( expiration = 60 * 100 )
def prev_article ( self ) :
"""
获取上一篇文章
: return : 上一篇文章对象
"""
# 前一篇
return Article . objects . filter ( id__lt = self . id , status = ' p ' ) . first ( )
def get_first_image_url ( self ) :
"""
从文章正文中获取第一张图片的URL
使用正则表达式匹配Markdown格式的图片
: return : 第一张图片的URL , 如果没有找到则返回空字符串
"""
match = re . search ( r ' ! \ [.*? \ ] \ ((.+?) \ ) ' , self . body )
if match :
return match . group ( 1 )
return " "
class Category ( BaseModel ) :
""" 文章分类 """
name = models . CharField (
_ ( ' category name ' ) ,
max_length = 30 ,
unique = True ,
help_text = ' 分类名称,必须唯一 ' )
parent_category = models . ForeignKey (
' self ' ,
verbose_name = _ ( ' parent category ' ) ,
blank = True ,
null = True ,
on_delete = models . CASCADE ,
help_text = ' 父级分类 ' )
slug = models . SlugField (
default = ' no-slug ' ,
max_length = 60 ,
blank = True ,
help_text = ' 分类slug, 用于生成URL ' )
index = models . IntegerField (
default = 0 ,
verbose_name = _ ( ' index ' ) ,
help_text = ' 分类索引,用于排序 ' )
class Meta :
ordering = [ ' -index ' ]
verbose_name = _ ( ' category ' )
verbose_name_plural = verbose_name
def get_absolute_url ( self ) :
"""
获取分类详情页URL
: return : 分类详情页URL
"""
return reverse (
' blog:category_detail ' , kwargs = {
' category_name ' : self . slug } )
def __str__ ( self ) :
return self . name
@cache_decorator ( 60 * 60 * 10 )
def get_category_tree ( self ) :
"""
递归获得分类目录的父级
: return : 包含当前分类及其所有父级分类的列表
"""
categorys = [ ]
def parse ( category ) :
categorys . append ( category )
if category . parent_category :
parse ( category . parent_category )
parse ( self )
return categorys
@cache_decorator ( 60 * 60 * 10 )
def get_sub_categorys ( self ) :
"""
获得当前分类目录所有子集
: return : 包含当前分类及其所有子分类的列表
"""
categorys = [ ]
all_categorys = Category . objects . all ( )
def parse ( category ) :
if category not in categorys :
categorys . append ( category )
childs = all_categorys . filter ( parent_category = category )
for child in childs :
if category not in categorys :
categorys . append ( child )
parse ( child )
parse ( self )
return categorys
class Tag ( BaseModel ) :
""" 文章标签 """
name = models . CharField (
_ ( ' tag name ' ) ,
max_length = 30 ,
unique = True ,
help_text = ' 标签名称,必须唯一 ' )
slug = models . SlugField (
default = ' no-slug ' ,
max_length = 60 ,
blank = True ,
help_text = ' 标签slug, 用于生成URL ' )
def __str__ ( self ) :
return self . name
def get_absolute_url ( self ) :
"""
获取标签详情页URL
: return : 标签详情页URL
"""
return reverse ( ' blog:tag_detail ' , kwargs = { ' tag_name ' : self . slug } )
@cache_decorator ( 60 * 60 * 10 )
def get_article_count ( self ) :
"""
获取使用该标签的文章数量
: return : 文章数量
"""
return Article . objects . filter ( tags__name = self . name ) . distinct ( ) . count ( )
class Meta :
ordering = [ ' name ' ]
verbose_name = _ ( ' tag ' )
verbose_name_plural = verbose_name
class Links ( models . Model ) :
""" 友情链接 """
name = models . CharField (
_ ( ' link name ' ) ,
max_length = 30 ,
unique = True ,
help_text = ' 链接名称 ' )
link = models . URLField (
_ ( ' link ' ) ,
help_text = ' 链接地址 ' )
sequence = models . IntegerField (
_ ( ' order ' ) ,
unique = True ,
help_text = ' 链接排序 ' )
is_enable = models . BooleanField (
_ ( ' is show ' ) ,
default = True ,
blank = False ,
null = False ,
help_text = ' 是否显示 ' )
show_type = models . CharField (
_ ( ' show type ' ) ,
max_length = 1 ,
choices = LinkShowType . choices ,
default = LinkShowType . I ,
help_text = ' 链接显示类型 ' )
creation_time = models . DateTimeField (
_ ( ' creation time ' ) ,
default = now ,
help_text = ' 链接创建时间 ' )
last_mod_time = models . DateTimeField (
_ ( ' modify time ' ) ,
default = now ,
help_text = ' 链接最后修改时间 ' )
class Meta :
ordering = [ ' sequence ' ]
verbose_name = _ ( ' link ' )
verbose_name_plural = verbose_name
def __str__ ( self ) :
return self . name
class SideBar ( models . Model ) :
""" 侧边栏,可以展示一些html内容 """
name = models . CharField (
_ ( ' title ' ) ,
max_length = 100 ,
help_text = ' 侧边栏标题 ' )
content = models . TextField (
_ ( ' content ' ) ,
help_text = ' 侧边栏内容, 支持HTML ' )
sequence = models . IntegerField (
_ ( ' order ' ) ,
unique = True ,
help_text = ' 侧边栏排序 ' )
is_enable = models . BooleanField (
_ ( ' is enable ' ) ,
default = True ,
help_text = ' 是否启用 ' )
creation_time = models . DateTimeField (
_ ( ' creation time ' ) ,
default = now ,
help_text = ' 侧边栏创建时间 ' )
last_mod_time = models . DateTimeField (
_ ( ' modify time ' ) ,
default = now ,
help_text = ' 侧边栏最后修改时间 ' )
class Meta :
ordering = [ ' sequence ' ]
verbose_name = _ ( ' sidebar ' )
verbose_name_plural = verbose_name
def __str__ ( self ) :
return self . name
class BlogSettings ( models . Model ) :
""" blog的配置 """
site_name = models . CharField (
_ ( ' site name ' ) ,
max_length = 200 ,
null = False ,
blank = False ,
default = ' ' ,
help_text = ' 网站名称 ' )
site_description = models . TextField (
_ ( ' site description ' ) ,
max_length = 1000 ,
null = False ,
blank = False ,
default = ' ' ,
help_text = ' 网站描述 ' )
site_seo_description = models . TextField (
_ ( ' site seo description ' ) ,
max_length = 1000 ,
null = False ,
blank = False ,
default = ' ' ,
help_text = ' 网站SEO描述 ' )
site_keywords = models . TextField (
_ ( ' site keywords ' ) ,
max_length = 1000 ,
null = False ,
blank = False ,
default = ' ' ,
help_text = ' 网站关键词 ' )
article_sub_length = models . IntegerField (
_ ( ' article sub length ' ) ,
default = 300 ,
help_text = ' 文章摘要长度 ' )
sidebar_article_count = models . IntegerField (
_ ( ' sidebar article count ' ) ,
default = 10 ,
help_text = ' 侧边栏文章显示数量 ' )
sidebar_comment_count = models . IntegerField (
_ ( ' sidebar comment count ' ) ,
default = 5 ,
help_text = ' 侧边栏评论显示数量 ' )
article_comment_count = models . IntegerField (
_ ( ' article comment count ' ) ,
default = 5 ,
help_text = ' 文章评论显示数量 ' )
show_google_adsense = models . BooleanField (
_ ( ' show adsense ' ) ,
default = False ,
help_text = ' 是否显示Google广告 ' )
google_adsense_codes = models . TextField (
_ ( ' adsense code ' ) ,
max_length = 2000 ,
null = True ,
blank = True ,
default = ' ' ,
help_text = ' Google广告代码 ' )
open_site_comment = models . BooleanField (
_ ( ' open site comment ' ) ,
default = True ,
help_text = ' 是否开放站点评论 ' )
global_header = models . TextField (
" 公共头部 " ,
null = True ,
blank = True ,
default = ' ' ,
help_text = ' 公共头部代码 ' )
global_footer = models . TextField (
" 公共尾部 " ,
null = True ,
blank = True ,
default = ' ' ,
help_text = ' 公共尾部代码 ' )
beian_code = models . CharField (
' 备案号 ' ,
max_length = 2000 ,
null = True ,
blank = True ,
default = ' ' ,
help_text = ' 网站备案号 ' )
analytics_code = models . TextField (
" 网站统计代码 " ,
max_length = 1000 ,
null = False ,
blank = False ,
default = ' ' ,
help_text = ' 网站统计代码,如百度统计 ' )
show_gongan_code = models . BooleanField (
' 是否显示公安备案号 ' ,
default = False ,
null = False ,
help_text = ' 是否显示公安备案号 ' )
gongan_beiancode = models . TextField (
' 公安备案号 ' ,
max_length = 2000 ,
null = True ,
blank = True ,
default = ' ' ,
help_text = ' 公安备案号 ' )
comment_need_review = models . BooleanField (
' 评论是否需要审核 ' ,
default = False ,
null = False ,
help_text = ' 评论是否需要审核 ' )
class Meta :
verbose_name = _ ( ' Website configuration ' )
verbose_name_plural = verbose_name
def __str__ ( self ) :
return self . site_name
def clean ( self ) :
"""
验证模型数据
确保只存在一个配置实例
"""
if BlogSettings . objects . exclude ( id = self . id ) . count ( ) :
raise ValidationError ( _ ( ' There can only be one configuration ' ) )
def save ( self , * args , * * kwargs ) :
"""
重写保存方法
保存后清除缓存
"""
super ( ) . save ( * args , * * kwargs )
from djangoblog . utils import cache
cache . clear ( )