From 4d6f98080e36b8bcbd43f902916576bae0284c55 Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Tue, 17 Mar 2026 20:59:24 +0800 Subject: [PATCH] =?UTF-8?q?admin=20=E6=89=8B=E6=9C=BA=E5=92=8C=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/community/admin.py | 38 +++++++++++++++++++++--- backend/competition/admin.py | 56 ++++++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/backend/community/admin.py b/backend/community/admin.py index 1558961..4372485 100644 --- a/backend/community/admin.py +++ b/backend/community/admin.py @@ -120,7 +120,7 @@ class OrderableAdminMixin: @admin.register(Activity) class ActivityAdmin(ModelAdmin): - list_display = ('title', 'author', 'banner_display', 'start_time', 'location', 'signup_count', 'is_visible', 'is_active', 'auto_confirm', 'created_at') + list_display = ('title', 'author_info_display', 'banner_display', 'start_time', 'location', 'signup_count', 'is_visible', 'is_active', 'auto_confirm', 'created_at') list_filter = ('is_visible', 'is_active', 'auto_confirm', 'start_time') search_fields = ('title', 'location', 'author__phone_number') # autocomplete_fields = ['author'] # 暂时注释,避免环境不一致导致报错 @@ -141,6 +141,14 @@ class ActivityAdmin(ModelAdmin): }), ) + @display(description="发布者 (手机号/昵称)") + def author_info_display(self, obj): + if not obj.author: + return "-" + phone = obj.author.phone_number or "无手机号" + nickname = obj.author.nickname or "无昵称" + return f"{phone} ({nickname})" + @display(description="Banner") def banner_display(self, obj): if obj.banner: @@ -155,7 +163,7 @@ class ActivityAdmin(ModelAdmin): @admin.register(ActivitySignup) class ActivitySignupAdmin(ModelAdmin): - list_display = ('activity', 'user', 'signup_time', 'status_label', 'order_link') + list_display = ('activity', 'user_info_display', 'signup_time', 'status_label', 'order_link') list_filter = ('status', 'signup_time', 'activity') search_fields = ('user__nickname', 'user__phone_number', 'activity__title') autocomplete_fields = ['activity', 'user'] @@ -172,6 +180,12 @@ class ActivitySignupAdmin(ModelAdmin): ) readonly_fields = ('signup_time', 'signup_info_display') + @display(description="报名用户 (手机号/昵称)") + def user_info_display(self, obj): + phone = obj.user.phone_number or "无手机号" + nickname = obj.user.nickname or "无昵称" + return f"{phone} ({nickname})" + @display(description="报名信息") def signup_info_display(self, obj): import json @@ -209,7 +223,7 @@ class ActivitySignupAdmin(ModelAdmin): @admin.register(Topic) class TopicAdmin(OrderableAdminMixin, ModelAdmin): - list_display = ('title', 'status', 'category', 'author', 'get_related_item', 'reply_count', 'view_count', 'is_pinned', 'created_at', 'order_actions') + list_display = ('title', 'status', 'category', 'author_info_display', 'get_related_item', 'reply_count', 'view_count', 'is_pinned', 'created_at', 'order_actions') list_filter = ('status', 'category', 'is_pinned', 'created_at', 'related_product', 'related_service', 'related_course') search_fields = ('title', 'content', 'author__nickname', 'author__phone_number') autocomplete_fields = ['author', 'related_product', 'related_service', 'related_course'] @@ -218,6 +232,14 @@ class TopicAdmin(OrderableAdminMixin, ModelAdmin): actions = ['reset_ordering', 'approve_topics', 'reject_topics'] list_editable = ('status', 'is_pinned', 'view_count') + @display(description="作者 (手机号/昵称)") + def author_info_display(self, obj): + if not obj.author: + return "-" + phone = obj.author.phone_number or "无手机号" + nickname = obj.author.nickname or "无昵称" + return f"{phone} ({nickname})" + @admin.action(description="批量通过审核") def approve_topics(self, request, queryset): rows_updated = queryset.update(status='published') @@ -277,7 +299,7 @@ class TopicAdmin(OrderableAdminMixin, ModelAdmin): @admin.register(Reply) class ReplyAdmin(ModelAdmin): - list_display = ('short_content', 'topic', 'author', 'is_pinned', 'like_count', 'created_at') + list_display = ('short_content', 'topic', 'author_info_display', 'is_pinned', 'like_count', 'created_at') list_filter = ('is_pinned', 'created_at') search_fields = ('content', 'author__nickname', 'author__phone_number', 'topic__title') autocomplete_fields = ['author', 'topic', 'reply_to'] @@ -295,6 +317,14 @@ class ReplyAdmin(ModelAdmin): ) readonly_fields = ('created_at',) + @display(description="回复者 (手机号/昵称)") + def author_info_display(self, obj): + if not obj.author: + return "-" + phone = obj.author.phone_number or "无手机号" + nickname = obj.author.nickname or "无昵称" + return f"{phone} ({nickname})" + @display(description="点赞数") def like_count(self, obj): return obj.likes.count() diff --git a/backend/competition/admin.py b/backend/competition/admin.py index 54d5f14..fe571e6 100644 --- a/backend/competition/admin.py +++ b/backend/competition/admin.py @@ -1,5 +1,6 @@ from django.contrib import admin from unfold.admin import ModelAdmin +from unfold.decorators import display from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment class ScoreDimensionInline(admin.TabularInline): @@ -45,11 +46,20 @@ class CompetitionAdmin(ModelAdmin): @admin.register(CompetitionEnrollment) class CompetitionEnrollmentAdmin(ModelAdmin): - list_display = ['competition', 'user', 'role', 'status', 'created_at'] + list_display = ['competition', 'user_info_display', 'role', 'status', 'created_at'] list_filter = ['competition', 'role', 'status'] - search_fields = ['user__nickname', 'competition__title'] + search_fields = ['user__nickname', 'user__phone_number', 'competition__title'] + autocomplete_fields = ['user', 'competition'] actions = ['approve_enrollment', 'reject_enrollment'] + @display(description="报名用户 (手机号/昵称)") + def user_info_display(self, obj): + if not obj.user: + return "-" + phone = obj.user.phone_number or "无手机号" + nickname = obj.user.nickname or "无昵称" + return f"{phone} ({nickname})" + def approve_enrollment(self, request, queryset): queryset.update(status='approved') approve_enrollment.short_description = "通过审核" @@ -60,9 +70,10 @@ class CompetitionEnrollmentAdmin(ModelAdmin): @admin.register(Project) class ProjectAdmin(ModelAdmin): - list_display = ['id', 'title', 'competition', 'contestant', 'status', 'final_score', 'created_at'] + list_display = ['id', 'title', 'competition', 'contestant_info_display', 'status', 'final_score', 'created_at'] list_filter = ['competition', 'status'] - search_fields = ['id', 'title', 'contestant__user__nickname'] + search_fields = ['id', 'title', 'contestant__user__nickname', 'contestant__user__phone_number'] + autocomplete_fields = ['competition', 'contestant'] inlines = [ProjectFileInline] readonly_fields = ['id', 'final_score'] @@ -79,17 +90,46 @@ class ProjectAdmin(ModelAdmin): }), ) + @display(description="参赛人员 (手机号/昵称)") + def contestant_info_display(self, obj): + if not obj.contestant or not obj.contestant.user: + return "-" + user = obj.contestant.user + phone = user.phone_number or "无手机号" + nickname = user.nickname or "无昵称" + return f"{phone} ({nickname})" + @admin.register(Score) class ScoreAdmin(ModelAdmin): - list_display = ['project', 'judge', 'dimension', 'score', 'created_at'] + list_display = ['project', 'judge_info_display', 'dimension', 'score', 'created_at'] list_filter = ['project__competition', 'dimension'] - search_fields = ['project__title', 'judge__user__nickname'] + search_fields = ['project__title', 'judge__user__nickname', 'judge__user__phone_number'] + autocomplete_fields = ['project', 'judge'] + + @display(description="评委 (手机号/昵称)") + def judge_info_display(self, obj): + if not obj.judge or not obj.judge.user: + return "-" + user = obj.judge.user + phone = user.phone_number or "无手机号" + nickname = user.nickname or "无昵称" + return f"{phone} ({nickname})" @admin.register(Comment) class CommentAdmin(ModelAdmin): - list_display = ['project', 'judge', 'content_preview', 'created_at'] + list_display = ['project', 'judge_info_display', 'content_preview', 'created_at'] list_filter = ['project__competition'] - search_fields = ['project__title', 'judge__user__nickname', 'content'] + search_fields = ['project__title', 'judge__user__nickname', 'judge__user__phone_number', 'content'] + autocomplete_fields = ['project', 'judge'] + + @display(description="评委 (手机号/昵称)") + def judge_info_display(self, obj): + if not obj.judge or not obj.judge.user: + return "-" + user = obj.judge.user + phone = user.phone_number or "无手机号" + nickname = user.nickname or "无昵称" + return f"{phone} ({nickname})" def content_preview(self, obj): return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content