This commit is contained in:
@@ -19,6 +19,19 @@ class CompetitionAdmin(ModelAdmin):
|
|||||||
search_fields = ['title', 'description']
|
search_fields = ['title', 'description']
|
||||||
inlines = [ScoreDimensionInline]
|
inlines = [ScoreDimensionInline]
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('基本信息', {
|
||||||
|
'fields': ('title', 'description', 'rule_description', 'condition_description')
|
||||||
|
}),
|
||||||
|
('封面设置', {
|
||||||
|
'fields': ('cover_image', 'cover_image_url'),
|
||||||
|
'description': '封面图可以上传本地图片,也可以填写外部链接,优先显示本地上传的图片'
|
||||||
|
}),
|
||||||
|
('时间和状态', {
|
||||||
|
'fields': ('start_time', 'end_time', 'status', 'is_active')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
actions = ['make_published', 'make_ended']
|
actions = ['make_published', 'make_ended']
|
||||||
|
|
||||||
def make_published(self, request, queryset):
|
def make_published(self, request, queryset):
|
||||||
@@ -51,6 +64,19 @@ class ProjectAdmin(ModelAdmin):
|
|||||||
search_fields = ['title', 'contestant__user__nickname']
|
search_fields = ['title', 'contestant__user__nickname']
|
||||||
inlines = [ProjectFileInline]
|
inlines = [ProjectFileInline]
|
||||||
readonly_fields = ['final_score']
|
readonly_fields = ['final_score']
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('基本信息', {
|
||||||
|
'fields': ('competition', 'contestant', 'title', 'description', 'team_info')
|
||||||
|
}),
|
||||||
|
('封面设置', {
|
||||||
|
'fields': ('cover_image', 'cover_image_url'),
|
||||||
|
'description': '封面图可以上传本地图片,也可以填写外部链接,优先显示本地上传的图片'
|
||||||
|
}),
|
||||||
|
('状态和得分', {
|
||||||
|
'fields': ('status', 'final_score')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
@admin.register(Score)
|
@admin.register(Score)
|
||||||
class ScoreAdmin(ModelAdmin):
|
class ScoreAdmin(ModelAdmin):
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 6.0.1 on 2026-03-10 02:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('competition', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='competition',
|
||||||
|
name='cover_image_url',
|
||||||
|
field=models.URLField(blank=True, help_text='优先使用上传的图片', null=True, verbose_name='封面图URL'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='project',
|
||||||
|
name='cover_image_url',
|
||||||
|
field=models.URLField(blank=True, help_text='优先使用上传的图片', null=True, verbose_name='项目封面URL'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -20,6 +20,7 @@ class Competition(models.Model):
|
|||||||
condition_description = models.TextField(verbose_name="参赛条件说明", blank=True)
|
condition_description = models.TextField(verbose_name="参赛条件说明", blank=True)
|
||||||
|
|
||||||
cover_image = models.ImageField(upload_to='competitions/covers/', verbose_name="封面图", null=True, blank=True)
|
cover_image = models.ImageField(upload_to='competitions/covers/', verbose_name="封面图", null=True, blank=True)
|
||||||
|
cover_image_url = models.URLField(verbose_name="封面图URL", null=True, blank=True, help_text="优先使用上传的图片")
|
||||||
|
|
||||||
start_time = models.DateTimeField(verbose_name="开始时间")
|
start_time = models.DateTimeField(verbose_name="开始时间")
|
||||||
end_time = models.DateTimeField(verbose_name="结束时间")
|
end_time = models.DateTimeField(verbose_name="结束时间")
|
||||||
@@ -111,6 +112,7 @@ class Project(models.Model):
|
|||||||
team_info = models.TextField(verbose_name="团队介绍", blank=True)
|
team_info = models.TextField(verbose_name="团队介绍", blank=True)
|
||||||
|
|
||||||
cover_image = models.ImageField(upload_to='competitions/projects/covers/', verbose_name="项目封面", null=True, blank=True)
|
cover_image = models.ImageField(upload_to='competitions/projects/covers/', verbose_name="项目封面", null=True, blank=True)
|
||||||
|
cover_image_url = models.URLField(verbose_name="项目封面URL", null=True, blank=True, help_text="优先使用上传的图片")
|
||||||
|
|
||||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name="状态")
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name="状态")
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,20 @@ class ScoreDimensionSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class CompetitionSerializer(serializers.ModelSerializer):
|
class CompetitionSerializer(serializers.ModelSerializer):
|
||||||
score_dimensions = ScoreDimensionSerializer(many=True, read_only=True)
|
score_dimensions = ScoreDimensionSerializer(many=True, read_only=True)
|
||||||
|
display_cover_image = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Competition
|
model = Competition
|
||||||
fields = ['id', 'title', 'description', 'rule_description', 'condition_description',
|
fields = ['id', 'title', 'description', 'rule_description', 'condition_description',
|
||||||
'cover_image', 'start_time', 'end_time', 'status', 'is_active',
|
'cover_image', 'cover_image_url', 'display_cover_image',
|
||||||
|
'start_time', 'end_time', 'status', 'is_active',
|
||||||
'score_dimensions', 'created_at']
|
'score_dimensions', 'created_at']
|
||||||
|
|
||||||
|
def get_display_cover_image(self, obj):
|
||||||
|
if obj.cover_image:
|
||||||
|
return obj.cover_image.url
|
||||||
|
return obj.cover_image_url
|
||||||
|
|
||||||
class CompetitionEnrollmentSerializer(serializers.ModelSerializer):
|
class CompetitionEnrollmentSerializer(serializers.ModelSerializer):
|
||||||
user = WeChatUserSerializer(read_only=True)
|
user = WeChatUserSerializer(read_only=True)
|
||||||
|
|
||||||
@@ -41,11 +48,13 @@ class ProjectFileSerializer(serializers.ModelSerializer):
|
|||||||
class ProjectSerializer(serializers.ModelSerializer):
|
class ProjectSerializer(serializers.ModelSerializer):
|
||||||
files = ProjectFileSerializer(many=True, read_only=True)
|
files = ProjectFileSerializer(many=True, read_only=True)
|
||||||
contestant_info = serializers.SerializerMethodField()
|
contestant_info = serializers.SerializerMethodField()
|
||||||
|
display_cover_image = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Project
|
model = Project
|
||||||
fields = ['id', 'competition', 'contestant', 'title', 'description', 'team_info',
|
fields = ['id', 'competition', 'contestant', 'title', 'description', 'team_info',
|
||||||
'cover_image', 'status', 'final_score', 'files', 'contestant_info', 'created_at']
|
'cover_image', 'cover_image_url', 'display_cover_image',
|
||||||
|
'status', 'final_score', 'files', 'contestant_info', 'created_at']
|
||||||
read_only_fields = ['final_score', 'contestant']
|
read_only_fields = ['final_score', 'contestant']
|
||||||
|
|
||||||
def get_contestant_info(self, obj):
|
def get_contestant_info(self, obj):
|
||||||
@@ -54,6 +63,11 @@ class ProjectSerializer(serializers.ModelSerializer):
|
|||||||
"avatar_url": obj.contestant.user.avatar_url
|
"avatar_url": obj.contestant.user.avatar_url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_display_cover_image(self, obj):
|
||||||
|
if obj.cover_image:
|
||||||
|
return obj.cover_image.url
|
||||||
|
return obj.cover_image_url
|
||||||
|
|
||||||
class ScoreSerializer(serializers.ModelSerializer):
|
class ScoreSerializer(serializers.ModelSerializer):
|
||||||
judge_name = serializers.CharField(source='judge.user.nickname', read_only=True)
|
judge_name = serializers.CharField(source='judge.user.nickname', read_only=True)
|
||||||
dimension_name = serializers.CharField(source='dimension.name', read_only=True)
|
dimension_name = serializers.CharField(source='dimension.name', read_only=True)
|
||||||
|
|||||||
@@ -317,6 +317,37 @@ UNFOLD = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "比赛管理",
|
||||||
|
"separator": True,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "比赛列表",
|
||||||
|
"icon": "emoji_events",
|
||||||
|
"link": reverse_lazy("admin:competition_competition_changelist"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "比赛人员/报名",
|
||||||
|
"icon": "group_add",
|
||||||
|
"link": reverse_lazy("admin:competition_competitionenrollment_changelist"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "参赛项目",
|
||||||
|
"icon": "lightbulb",
|
||||||
|
"link": reverse_lazy("admin:competition_project_changelist"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "评分记录",
|
||||||
|
"icon": "score",
|
||||||
|
"link": reverse_lazy("admin:competition_score_changelist"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "评委评语",
|
||||||
|
"icon": "rate_review",
|
||||||
|
"link": reverse_lazy("admin:competition_comment_changelist"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "系统配置",
|
"title": "系统配置",
|
||||||
"separator": True,
|
"separator": True,
|
||||||
|
|||||||
Reference in New Issue
Block a user