|
|
# 导入Django表单模块,用于创建自定义表单
|
|
|
from django import forms
|
|
|
# 导入Django admin模块,用于配置后台管理界面
|
|
|
from django.contrib import admin
|
|
|
# 导入Django用户模型获取工具,兼容自定义用户模型场景
|
|
|
from django.contrib.auth import get_user_model
|
|
|
# 导入Django URL反向解析模块,用于生成后台管理页面的链接
|
|
|
from django.urls import reverse
|
|
|
# 导入Django HTML格式化工具,用于在后台显示自定义HTML内容(如链接)
|
|
|
from django.utils.html import format_html
|
|
|
# 导入Django国际化翻译工具,用于实现后台文字的多语言支持
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
|
# 注册自定义模型到admin后台的标识注释(固定写法)
|
|
|
# Register your models here.
|
|
|
# 从当前应用的models.py文件中导入Article模型(文章模型)
|
|
|
from .models import Article
|
|
|
|
|
|
|
|
|
# 自定义Article模型的列表页过滤器,继承自Django内置的SimpleListFilter
|
|
|
class ArticleListFilter(admin.SimpleListFilter):
|
|
|
# 过滤器在后台页面显示的标题(支持国际化),这里是“作者”
|
|
|
title = _("author")
|
|
|
# 过滤器对应的URL参数名,用于URL中传递过滤条件(如?author=1)
|
|
|
parameter_name = 'author'
|
|
|
|
|
|
# 定义过滤器的选项列表,返回(值, 显示文本)格式的元组
|
|
|
def lookups(self, request, model_admin):
|
|
|
# 1. 从Article模型中获取所有文章的作者,用set去重(避免同一作者多次出现)
|
|
|
# 2. 转换为list便于遍历,map函数提取每篇文章的author字段
|
|
|
authors = list(set(map(lambda x: x.author, Article.objects.all())))
|
|
|
# 遍历去重后的作者列表,生成过滤器选项
|
|
|
for author in authors:
|
|
|
# 选项值为作者ID(用于数据库查询),显示文本为作者用户名(支持国际化)
|
|
|
yield (author.id, _(author.username))
|
|
|
|
|
|
# 根据过滤器选择的参数,过滤文章查询集(queryset)
|
|
|
def queryset(self, request, queryset):
|
|
|
# 获取当前过滤器选中的参数值(即作者ID)
|
|
|
id = self.value()
|
|
|
# 如果有选中的作者ID,返回该作者的所有文章
|
|
|
if id:
|
|
|
return queryset.filter(author__id__exact=id)
|
|
|
# 如果未选中任何作者,返回全部文章查询集
|
|
|
else:
|
|
|
return queryset
|
|
|
|
|
|
|
|
|
# 自定义Article模型的表单类,继承自Django内置的ModelForm
|
|
|
class ArticleForm(forms.ModelForm):
|
|
|
# 注释:此处原本计划使用AdminPagedownWidget富文本编辑器渲染body字段,暂未启用
|
|
|
# body = forms.CharField(widget=AdminPagedownWidget())
|
|
|
|
|
|
# 表单元数据配置类,用于关联模型与字段
|
|
|
class Meta:
|
|
|
# 关联的模型为Article(表示该表单用于操作Article模型数据)
|
|
|
model = Article
|
|
|
# 表单包含模型的所有字段(__all__为通配符,也可指定具体字段列表)
|
|
|
fields = '__all__'
|
|
|
|
|
|
|
|
|
# 自定义批量操作函数:将选中的文章状态设为“已发布”(假设status='p'代表发布)
|
|
|
def makr_article_publish(modeladmin, request, queryset):
|
|
|
# 批量更新选中的文章查询集,将status字段设为'p'
|
|
|
queryset.update(status='p')
|
|
|
|
|
|
|
|
|
# 自定义批量操作函数:将选中的文章状态设为“草稿”(假设status='d'代表草稿)
|
|
|
def draft_article(modeladmin, request, queryset):
|
|
|
# 批量更新选中的文章查询集,将status字段设为'd'
|
|
|
queryset.update(status='d')
|
|
|
|
|
|
|
|
|
# 自定义批量操作函数:关闭选中文章的评论功能(假设comment_status='c'代表关闭)
|
|
|
def close_article_commentstatus(modeladmin, request, queryset):
|
|
|
# 批量更新选中的文章查询集,将comment_status字段设为'c'
|
|
|
queryset.update(comment_status='c')
|
|
|
|
|
|
|
|
|
# 自定义批量操作函数:开启选中文章的评论功能(假设comment_status='o'代表开启)
|
|
|
def open_article_commentstatus(modeladmin, request, queryset):
|
|
|
# 批量更新选中的文章查询集,将comment_status字段设为'o'
|
|
|
queryset.update(comment_status='o')
|
|
|
|
|
|
|
|
|
# 为批量操作函数设置后台显示名称(支持国际化),显示在“动作”下拉菜单中
|
|
|
makr_article_publish.short_description = _('Publish selected articles') # “发布选中的文章”
|
|
|
draft_article.short_description = _('Draft selected articles') # “将选中的文章设为草稿”
|
|
|
close_article_commentstatus.short_description = _('Close article comments') # “关闭选中文章的评论”
|
|
|
open_article_commentstatus.short_description = _('Open article comments') # “开启选中文章的评论”
|
|
|
|
|
|
|
|
|
# 自定义Article模型的Admin配置类,继承自Django内置的ModelAdmin
|
|
|
class ArticlelAdmin(admin.ModelAdmin):
|
|
|
# 后台列表页每页显示的文章数量,这里是20条/页
|
|
|
list_per_page = 20
|
|
|
# 后台列表页的搜索框配置,支持搜索文章的“内容(body)”和“标题(title)”字段
|
|
|
search_fields = ('body', 'title')
|
|
|
# 后台添加/编辑文章时使用的自定义表单,即上面定义的ArticleForm
|
|
|
form = ArticleForm
|
|
|
# 后台列表页显示的字段列表,按顺序展示
|
|
|
list_display = (
|
|
|
'id', # 文章ID
|
|
|
'title', # 文章标题
|
|
|
'author', # 文章作者
|
|
|
'link_to_category', # 自定义字段:文章分类(带跳转链接)
|
|
|
'creation_time', # 文章创建时间
|
|
|
'views', # 文章浏览量
|
|
|
'status', # 文章状态(发布/草稿等)
|
|
|
'type', # 文章类型(如原创/转载等,需在Article模型中定义)
|
|
|
'article_order' # 文章排序权重(用于自定义排序)
|
|
|
)
|
|
|
# 后台列表页中,点击哪些字段可以跳转到文章编辑页
|
|
|
list_display_links = ('id', 'title')
|
|
|
# 后台列表页的过滤器配置,包含自定义的作者过滤器和内置字段过滤器
|
|
|
list_filter = (ArticleListFilter, 'status', 'type', 'category', 'tags')
|
|
|
# 多对多字段(tags标签)的编辑界面样式,使用水平选择框(默认是垂直)
|
|
|
filter_horizontal = ('tags',)
|
|
|
# 后台添加/编辑文章时,隐藏的字段(不允许管理员手动修改)
|
|
|
exclude = ('creation_time', 'last_modify_time')
|
|
|
# 是否显示“在站点上查看”按钮(跳转到文章的前台页面)
|
|
|
view_on_site = True
|
|
|
# 后台列表页的批量操作功能列表,关联上面定义的4个批量操作函数
|
|
|
actions = [
|
|
|
makr_article_publish,
|
|
|
draft_article,
|
|
|
close_article_commentstatus,
|
|
|
open_article_commentstatus]
|
|
|
|
|
|
# 自定义列表页字段:显示文章分类,并添加跳转到分类编辑页的链接
|
|
|
def link_to_category(self, obj):
|
|
|
# 1. 获取文章分类(obj.category)的模型元数据(应用名、模型名)
|
|
|
# 2. 用于生成admin后台分类编辑页的URL
|
|
|
info = (obj.category._meta.app_label, obj.category._meta.model_name)
|
|
|
# 3. 反向解析分类编辑页的URL,参数为分类ID(obj.category.id)
|
|
|
link = reverse('admin:%s_%s_change' % info, args=(obj.category.id,))
|
|
|
# 4. 生成HTML链接,显示分类名称,点击跳转到分类编辑页
|
|
|
return format_html(u'<a href="%s">%s</a>' % (link, obj.category.name))
|
|
|
|
|
|
# 自定义字段“link_to_category”在后台列表页的显示标题(支持国际化)
|
|
|
link_to_category.short_description = _('category')
|
|
|
|
|
|
# 重写获取表单的方法,自定义作者字段(author)的可选值
|
|
|
def get_form(self, request, obj=None, **kwargs):
|
|
|
# 1. 先调用父类的get_form方法,获取默认表单
|
|
|
form = super(ArticlelAdmin, self).get_form(request, obj, **kwargs)
|
|
|
# 2. 限制作者字段的可选范围:仅显示超级用户(is_superuser=True)
|
|
|
form.base_fields['author'].queryset = get_user_model(
|
|
|
).objects.filter(is_superuser=True)
|
|
|
# 3. 返回修改后的表单
|
|
|
return form
|
|
|
|
|
|
# 重写保存模型的方法(此处未修改逻辑,仅保留父类功能,便于后续扩展)
|
|
|
def save_model(self, request, obj, form, change):
|
|
|
# 调用父类的save_model方法,完成默认的保存逻辑(如更新时间、权限验证等)
|
|
|
super(ArticlelAdmin, self).save_model(request, obj, form, change)
|
|
|
|
|
|
# 重写“在站点上查看”的链接地址,跳转到文章的前台完整URL
|
|
|
def get_view_on_site_url(self, obj=None):
|
|
|
# 如果有具体的文章对象(obj不为空),调用文章模型的get_full_url方法获取前台URL
|
|
|
if obj:
|
|
|
url = obj.get_full_url()
|
|
|
return url
|
|
|
# 如果没有文章对象(如在列表页顶部的“查看站点”按钮),返回当前站点的域名
|
|
|
else:
|
|
|
# 从自定义工具模块导入获取当前站点的函数(需确保djangoblog.utils存在)
|
|
|
from djangoblog.utils import get_current_site
|
|
|
# 获取当前站点的域名(如www.example.com)
|
|
|
site = get_current_site().domain
|
|
|
return site
|
|
|
|
|
|
|
|
|
# 自定义Tag模型(标签模型)的Admin配置类(假设Tag模型在models.py中定义)
|
|
|
class TagAdmin(admin.ModelAdmin):
|
|
|
# 后台添加/编辑标签时,隐藏的字段(不允许手动修改)
|
|
|
exclude = ('slug', 'last_mod_time', 'creation_time')
|
|
|
|
|
|
|
|
|
# 自定义Category模型(分类模型)的Admin配置类(假设Category模型在models.py中定义)
|
|
|
class CategoryAdmin(admin.ModelAdmin):
|
|
|
# 后台分类列表页显示的字段:分类名称、父分类、排序索引
|
|
|
list_display = ('name', 'parent_category', 'index')
|
|
|
# 后台添加/编辑分类时,隐藏的字段(不允许手动修改)
|
|
|
exclude = ('slug', 'last_mod_time', 'creation_time')
|
|
|
|
|
|
|
|
|
# 自定义Links模型(友情链接模型)的Admin配置类(假设Links模型在models.py中定义)
|
|
|
class LinksAdmin(admin.ModelAdmin):
|
|
|
# 后台添加/编辑友情链接时,隐藏的字段(不允许手动修改)
|
|
|
exclude = ('last_mod_time', 'creation_time')
|
|
|
|
|
|
|
|
|
# 自定义SideBar模型(侧边栏模型)的Admin配置类(假设SideBar模型在models.py中定义)
|
|
|
class SideBarAdmin(admin.ModelAdmin):
|
|
|
# 后台侧边栏列表页显示的字段:名称、内容、是否启用、排序序号
|
|
|
list_display = ('name', 'content', 'is_enable', 'sequence')
|
|
|
# 后台添加/编辑侧边栏时,隐藏的字段(不允许手动修改)
|
|
|
exclude = ('last_mod_time', 'creation_time')
|
|
|
|
|
|
|
|
|
# 自定义BlogSettings模型(博客设置模型)的Admin配置类(假设BlogSettings模型在models.py中定义)
|
|
|
class BlogSettingsAdmin(admin.ModelAdmin):
|
|
|
# 空配置,使用ModelAdmin的默认功能(如需自定义可后续添加字段)
|
|
|
pass |