From 752b7caf71757d555efd769708a0fbd6384a224e Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Wed, 11 Feb 2026 15:03:22 +0800 Subject: [PATCH] finish --- backend/community/admin.py | 4 ++- ...tivity_banner_url_alter_activity_banner.py | 23 ++++++++++++++++++ backend/community/models.py | 21 +++++++++++++++- backend/community/serializers.py | 2 ++ .../__pycache__/settings.cpython-313.pyc | Bin 5772 -> 6264 bytes .../config/__pycache__/urls.cpython-313.pyc | Bin 1166 -> 1243 bytes backend/db.sqlite3 | Bin 372736 -> 380928 bytes .../shop/__pycache__/admin.cpython-313.pyc | Bin 16823 -> 17059 bytes .../shop/__pycache__/models.cpython-313.pyc | Bin 26639 -> 26637 bytes .../shop/__pycache__/views.cpython-313.pyc | Bin 52011 -> 52009 bytes 10 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 backend/community/migrations/0004_activity_banner_url_alter_activity_banner.py diff --git a/backend/community/admin.py b/backend/community/admin.py index 1d6bfaa..1a6d3af 100644 --- a/backend/community/admin.py +++ b/backend/community/admin.py @@ -37,7 +37,7 @@ class ActivityAdmin(ModelAdmin): fieldsets = ( ('基本信息', { - 'fields': ('title', 'description', 'banner', 'is_active') + 'fields': ('title', 'description', 'banner', 'banner_url', 'is_active') }), ('时间与地点', { 'fields': ('start_time', 'end_time', 'location'), @@ -52,6 +52,8 @@ class ActivityAdmin(ModelAdmin): def banner_display(self, obj): if obj.banner: return format_html('', obj.banner.url) + elif obj.banner_url: + return format_html('', obj.banner_url) return "暂无" @display(description="报名人数") diff --git a/backend/community/migrations/0004_activity_banner_url_alter_activity_banner.py b/backend/community/migrations/0004_activity_banner_url_alter_activity_banner.py new file mode 100644 index 0000000..0871a9d --- /dev/null +++ b/backend/community/migrations/0004_activity_banner_url_alter_activity_banner.py @@ -0,0 +1,23 @@ +# Generated by Django 6.0.1 on 2026-02-11 07:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('community', '0003_alter_reply_content_alter_topic_content_topicmedia'), + ] + + operations = [ + migrations.AddField( + model_name='activity', + name='banner_url', + field=models.URLField(blank=True, help_text='可直接填写图片链接,若同时上传图片,将优先显示上传的图片', null=True, verbose_name='活动Banner链接'), + ), + migrations.AlterField( + model_name='activity', + name='banner', + field=models.ImageField(blank=True, null=True, upload_to='activities/banners/', verbose_name='活动Banner图'), + ), + ] diff --git a/backend/community/models.py b/backend/community/models.py index c9c082d..1c756f4 100644 --- a/backend/community/models.py +++ b/backend/community/models.py @@ -7,7 +7,8 @@ class Activity(models.Model): """ title = models.CharField(max_length=100, verbose_name="活动标题") description = models.TextField(verbose_name="活动详情") - banner = models.ImageField(upload_to='activities/banners/', verbose_name="活动Banner图") + banner = models.ImageField(upload_to='activities/banners/', verbose_name="活动Banner图", null=True, blank=True) + banner_url = models.URLField(verbose_name="活动Banner链接", null=True, blank=True, help_text="可直接填写图片链接,若同时上传图片,将优先显示上传的图片") start_time = models.DateTimeField(verbose_name="开始时间") end_time = models.DateTimeField(verbose_name="结束时间") location = models.CharField(max_length=100, verbose_name="活动地点") @@ -15,6 +16,24 @@ class Activity(models.Model): is_active = models.BooleanField(default=True, verbose_name="是否启用") created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") + def clean(self): + from django.core.exceptions import ValidationError + if not self.banner and not self.banner_url: + raise ValidationError("Banner图片和Banner链接必须至少填写一项") + + def save(self, *args, **kwargs): + self.clean() + super().save(*args, **kwargs) + + @property + def display_banner_url(self): + """ + 获取Banner显示的URL,优先使用上传的图片 + """ + if self.banner: + return self.banner.url + return self.banner_url + def __str__(self): return self.title diff --git a/backend/community/serializers.py b/backend/community/serializers.py index 2c226f2..b3c6a0c 100644 --- a/backend/community/serializers.py +++ b/backend/community/serializers.py @@ -3,6 +3,8 @@ from .models import Activity, ActivitySignup, Topic, Reply, TopicMedia from shop.serializers import WeChatUserSerializer, ESP32ConfigSerializer, ServiceSerializer, VCCourseSerializer class ActivitySerializer(serializers.ModelSerializer): + display_banner_url = serializers.ReadOnlyField() + class Meta: model = Activity fields = '__all__' diff --git a/backend/config/__pycache__/settings.cpython-313.pyc b/backend/config/__pycache__/settings.cpython-313.pyc index f89d6471cc831ea184a2e9de244b687d7710b4a9..505eb1346157a73b291f7d1294e76bff96610fa1 100644 GIT binary patch delta 761 zcmeCt{b8W-nU|M~0SHP}dNRAz85kaeI4~d#Wqj6S-l#EysXjP4I3-3-i6J=Elo28o zY^%o{oEDr87R^8w)n^HI0m@|tvj%4cXM^Q)kmZAOgY&?m`N*RBOdwtQtic69y@h(L zMe@O{MGC=1!4|>A!O|tcr3Q=!jKRhFjKO8W<$6rP6?!a1is?+6m79MswKFpEPHtd% z&3%hAIX^eIG%vHHa&tDTHZvQ@A5|Wc1KC72Z{YaD!e}&kE$?b&4xnh5^NaQSp0DV> z#a5i0k)NMaC6}0zo0(@-oRMD;UzWVNp3j)Eo*$_2`I3E4dv-n9(f4BAuBUTnm+}C` zo^9Fvv}?ulbqk+QXuHLlT9%quQl$*h4|hO(Vsc4l8PFy1$r*`x>8UxH#U)6ZpLH#L zI-&O#S4Mt$d`W(MQEGaXCb|jrFe8dH)ALFTkPQ+7xuUD#*_`zdXFc69?djSHw^-Bi zi%N5=6wpm7$uG!EM%EAV1w_x&+4G(*>Al4bbY)3=QfX3BPAW`4Kf*IbsRcQeo0swD zGBO5j77?7p$f!Jdxlkil70?_|iYVSQ*+|%zoll6Vf$x*T<~HH?jJ!HG6f|xs=v>hC zy{zCjSx;1Y@?6oRaP1qiiXYe*lnibtsDovLE-M6oWM>f-`@jPh)d7n}TvmvLi<-gI z`d?NEfQtf6&;_dniB5ha>L*^$l+P&6^^v`pQGo5Ex;qmWQv=(FFqX-IV&*IrKvx0) D|91h2 delta 285 zcmexi(4(vInU|M~0SFehcV{LkGcY^`abQ3Q%J_VSX`{vrCJTM0U>7}ReU{*4J?7vP zJ=P-mVAdjq;M8D?;I!cM;0yys1IFMqea7I-;4D3+;A}mXBE@tj&793q% zyxx3+RhyYnXfq3^C@Z7kWGTMY>LB~WJe^!$tl#&1MfWYX;^d6{{G2L<#FX63Jgef2 z{DOFp^yU|Q#*CXy1QQtSqV PBr#96l`v;12AT!{3{g!r diff --git a/backend/config/__pycache__/urls.cpython-313.pyc b/backend/config/__pycache__/urls.cpython-313.pyc index 0bb9968984fea7c11da2f871bc788d5c7e497df6..3134b720115d552b53f2064bfe826a0b996ec6f2 100644 GIT binary patch delta 231 zcmeClK`m?;y4j$sCh za!)*`$jcMVYsn1e^2KmZydWkL%oEIS$rvmE7Z;4-0gCfM#f3oP`fQWE7{mF6EtzzA z85oKL(nZomG({(GV4N()mspUgpPZkYTbh?yQmJ3X2WM}#Wtzgscy#h5W?R9VEF2d& iC1;vnP&U3SZE~5#bTU7SCx;*>KT`wu2Z_lEEP4R_Kr{RR delta 174 zcmcc3*~h8=nU|M~0SF>Ix-`hu diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 5342bc5b5cc8fb4a2eac9a941d550aa43988421b..44244baff8c2e3dd5843b7ecfc9ca5124a4407e2 100644 GIT binary patch delta 761 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 b29vvA8pB4D$8>R0&Rq#tckR(bi)8j6mou7# diff --git a/backend/shop/__pycache__/models.cpython-313.pyc b/backend/shop/__pycache__/models.cpython-313.pyc index 02189486e8aa4d6e8647b6f66d47807b5cae352d..140b8db23456eac3723b8038dbfc9562ca4737d4 100644 GIT binary patch delta 41 ucmeCbz}S0%k@qt%FBbz4==OAH?%T+#6~QeFLD`h5mIJGn0}b;H4GI7N005qei)rGq4aYMD3RX!%MYGp4$O9E1*A^(z7AV&i lEYTJ$um{iv$Qw+0tXt`4<^wMCX)d>L9_QdGLS<391Q>f