Files
server/article/admin.py
T

188 lines
6.6 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django import forms
from django.contrib import admin
from django.utils.html import format_html
from import_export.admin import ImportExportModelAdmin
from article.models import NoticeReceipt, Notice, Article, Carousel, ArticleAttachment
from base.models import MainMenu
from users.models import User
# —————— 板块 ——————
# @admin.register(ArticleSection)
# class SectionAdmin(admin.ModelAdmin):
# list_display = ('display_name', 'code', 'parent', 'is_enabled', 'order')
# list_filter = ('parent', 'enabled')
# search_fields = ('name', 'code')
# ordering = ('order', 'name')
# list_editable = ('order',)
# fieldsets = (
# ('基本信息', {
# 'fields': ('name', 'code', 'parent', 'enabled', 'order')
# }),
# )
#
# def display_name(self, obj):
# """在列表中显示层级缩进"""
# if obj.is_sub:
# return f" └─ {obj.name}" # 使用全角空格+符号模拟缩进
# return obj.name
#
# display_name.short_description = '板块名称'
# display_name.admin_order_field = 'name'
#
# def is_enabled(self, obj):
# return obj.enabled
#
# is_enabled.boolean = True
# is_enabled.short_description = '启用'
#
# def formfield_for_foreignkey(self, db_field, request, **kwargs):
# """限制 parent 只能选择主板块(无父级的板块)"""
# if db_field.name == "parent":
# kwargs["queryset"] = ArticleSection.objects.filter(parent__isnull=True)
# return super().formfield_for_foreignkey(db_field, request, **kwargs)
#
# def get_queryset(self, request):
# """优化查询,避免 N+1"""
# return super().get_queryset(request).select_related('parent')
#
# —————— 轮播图 ——————
@admin.register(Carousel)
class CarouselAdmin(ImportExportModelAdmin):
list_display = ('title', 'image_thumb', 'link_url', 'order', 'active')
list_editable = ('order', 'active')
ordering = ('order',)
def image_thumb(self, obj):
if obj.image:
return format_html('<image src="{}" width="60" height="auto" />', obj.image.url)
return "无图"
image_thumb.short_description = "预览"
# --- 附件内联配置 ---
class ArticleAttachmentInline(admin.TabularInline):
model = ArticleAttachment
extra = 1 # 默认显示 1 个空白的附件上传框
verbose_name = "附件"
verbose_name_plural = "附件列表"
# 如果附件较多,可以限制每页显示数量
# max_num = 5
# 1. 定义自定义表单
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 核心代码:过滤 section 字段,只保留有父级的分类(即二级分类)
# 这里的 queryset 会直接作用于 Admin 的下拉选择框
self.fields['section'].queryset = MainMenu.objects.filter(parent__isnull=False, visible=True)
# 可选:优化显示格式,让用户知道是哪个主板块下的子板块
# 例如显示:"[新闻中心] 国内新闻"
self.fields['section'].label_from_instance = lambda obj: f"[{obj.parent.title}] {obj.title}"
# —————— 文章 ——————
@admin.register(Article)
class ArticleAdmin(ImportExportModelAdmin):
form = ArticleForm # <--- 关联自定义表单
list_display = ('title', 'section', 'author', 'is_published', 'created_at', 'attachment_count')
list_filter = ('section', 'is_published', 'created_at')
search_fields = ('title', 'content')
date_hierarchy = 'created_at'
autocomplete_fields = ('author',) # 需要 UserAdmin 支持搜索
# 核心配置:将附件内联注册到文章管理中
inlines = [ArticleAttachmentInline]
fieldsets = (
('基本信息', {'fields': ('title', 'section', 'cover')}),
('内容', {'fields': ('content',)}),
('发布设置', {'fields': ('is_published',)}),
)
# 2. 定义显示附件数量的方法
def attachment_count(self, obj):
# 使用 count() 方法统计数量
count = obj.attachments.count()
if count == 0:
return "-" # 没有附件显示横杠
return f"📎 {count}" # 有附件显示图标和数量
# 3. 设置该列在后台的标题
attachment_count.short_description = "附件"
# —————— 通知(带签收) ——————
@admin.register(Notice)
class NoticeAdmin(ImportExportModelAdmin):
list_display = (
'title',
'publisher',
'require_sign',
'is_published',
'signed_count',
'total_target_users',
'created_at'
)
list_filter = ('require_sign', 'is_published', 'created_at', 'target_departments')
search_fields = ('title', 'content')
filter_horizontal = ('target_departments',)
readonly_fields = ('created_at', 'updated_at', 'publisher')
date_hierarchy = 'created_at'
fieldsets = (
('基本信息', {
'fields': ('title', 'content', 'is_published')
}),
('签收设置', {
'fields': ('require_sign', 'target_departments'),
'description': '勾选“是否需要签收”后,可指定接收部门。未指定则默认全员可见但不可签收。'
}),
('时间信息', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def save_model(self, request, obj, form, change):
if not change:
obj.publisher = request.user
super().save_model(request, obj, form, change)
def signed_count(self, obj):
return obj.receipts.count()
signed_count.short_description = "已签收人数"
def total_target_users(self, obj):
if obj.target_departments.exists():
count = User.objects.filter(
dept__in=obj.target_departments.all(),
is_active=True
).count()
else:
count = User.objects.filter(is_active=True).count()
return count
total_target_users.short_description = "应签收人数"
# —————— 签收记录 ——————
@admin.register(NoticeReceipt)
class NoticeReceiptAdmin(ImportExportModelAdmin):
list_display = ('notice', 'user', 'signed_at')
list_filter = ('signed_at', 'notice__title')
search_fields = ('user__cname', 'user__username', 'notice__title')
readonly_fields = ('notice', 'user', 'signed_at')
def has_add_permission(self, request):
return False # 禁止手动添加