admin 手机和用户名
All checks were successful
Deploy to Server / deploy (push) Successful in 16s

This commit is contained in:
jeremygan2021
2026-03-17 20:59:24 +08:00
parent de1e409447
commit 4d6f98080e
2 changed files with 82 additions and 12 deletions

View File

@@ -120,7 +120,7 @@ class OrderableAdminMixin:
@admin.register(Activity) @admin.register(Activity)
class ActivityAdmin(ModelAdmin): 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') list_filter = ('is_visible', 'is_active', 'auto_confirm', 'start_time')
search_fields = ('title', 'location', 'author__phone_number') search_fields = ('title', 'location', 'author__phone_number')
# autocomplete_fields = ['author'] # 暂时注释,避免环境不一致导致报错 # 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") @display(description="Banner")
def banner_display(self, obj): def banner_display(self, obj):
if obj.banner: if obj.banner:
@@ -155,7 +163,7 @@ class ActivityAdmin(ModelAdmin):
@admin.register(ActivitySignup) @admin.register(ActivitySignup)
class ActivitySignupAdmin(ModelAdmin): 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') list_filter = ('status', 'signup_time', 'activity')
search_fields = ('user__nickname', 'user__phone_number', 'activity__title') search_fields = ('user__nickname', 'user__phone_number', 'activity__title')
autocomplete_fields = ['activity', 'user'] autocomplete_fields = ['activity', 'user']
@@ -172,6 +180,12 @@ class ActivitySignupAdmin(ModelAdmin):
) )
readonly_fields = ('signup_time', 'signup_info_display') 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="报名信息") @display(description="报名信息")
def signup_info_display(self, obj): def signup_info_display(self, obj):
import json import json
@@ -209,7 +223,7 @@ class ActivitySignupAdmin(ModelAdmin):
@admin.register(Topic) @admin.register(Topic)
class TopicAdmin(OrderableAdminMixin, ModelAdmin): 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') list_filter = ('status', 'category', 'is_pinned', 'created_at', 'related_product', 'related_service', 'related_course')
search_fields = ('title', 'content', 'author__nickname', 'author__phone_number') search_fields = ('title', 'content', 'author__nickname', 'author__phone_number')
autocomplete_fields = ['author', 'related_product', 'related_service', 'related_course'] autocomplete_fields = ['author', 'related_product', 'related_service', 'related_course']
@@ -218,6 +232,14 @@ class TopicAdmin(OrderableAdminMixin, ModelAdmin):
actions = ['reset_ordering', 'approve_topics', 'reject_topics'] actions = ['reset_ordering', 'approve_topics', 'reject_topics']
list_editable = ('status', 'is_pinned', 'view_count') 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="批量通过审核") @admin.action(description="批量通过审核")
def approve_topics(self, request, queryset): def approve_topics(self, request, queryset):
rows_updated = queryset.update(status='published') rows_updated = queryset.update(status='published')
@@ -277,7 +299,7 @@ class TopicAdmin(OrderableAdminMixin, ModelAdmin):
@admin.register(Reply) @admin.register(Reply)
class ReplyAdmin(ModelAdmin): 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') list_filter = ('is_pinned', 'created_at')
search_fields = ('content', 'author__nickname', 'author__phone_number', 'topic__title') search_fields = ('content', 'author__nickname', 'author__phone_number', 'topic__title')
autocomplete_fields = ['author', 'topic', 'reply_to'] autocomplete_fields = ['author', 'topic', 'reply_to']
@@ -295,6 +317,14 @@ class ReplyAdmin(ModelAdmin):
) )
readonly_fields = ('created_at',) 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="点赞数") @display(description="点赞数")
def like_count(self, obj): def like_count(self, obj):
return obj.likes.count() return obj.likes.count()

View File

@@ -1,5 +1,6 @@
from django.contrib import admin from django.contrib import admin
from unfold.admin import ModelAdmin from unfold.admin import ModelAdmin
from unfold.decorators import display
from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment from .models import Competition, CompetitionEnrollment, ScoreDimension, Project, ProjectFile, Score, Comment
class ScoreDimensionInline(admin.TabularInline): class ScoreDimensionInline(admin.TabularInline):
@@ -45,11 +46,20 @@ class CompetitionAdmin(ModelAdmin):
@admin.register(CompetitionEnrollment) @admin.register(CompetitionEnrollment)
class CompetitionEnrollmentAdmin(ModelAdmin): 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'] 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'] 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): def approve_enrollment(self, request, queryset):
queryset.update(status='approved') queryset.update(status='approved')
approve_enrollment.short_description = "通过审核" approve_enrollment.short_description = "通过审核"
@@ -60,9 +70,10 @@ class CompetitionEnrollmentAdmin(ModelAdmin):
@admin.register(Project) @admin.register(Project)
class ProjectAdmin(ModelAdmin): 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'] 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] inlines = [ProjectFileInline]
readonly_fields = ['id', 'final_score'] 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) @admin.register(Score)
class ScoreAdmin(ModelAdmin): 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'] 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) @admin.register(Comment)
class CommentAdmin(ModelAdmin): 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'] 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): def content_preview(self, obj):
return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content