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 f89d647..505eb13 100644 Binary files a/backend/config/__pycache__/settings.cpython-313.pyc and b/backend/config/__pycache__/settings.cpython-313.pyc differ diff --git a/backend/config/__pycache__/urls.cpython-313.pyc b/backend/config/__pycache__/urls.cpython-313.pyc index 0bb9968..3134b72 100644 Binary files a/backend/config/__pycache__/urls.cpython-313.pyc and b/backend/config/__pycache__/urls.cpython-313.pyc differ diff --git a/backend/db.sqlite3 b/backend/db.sqlite3 index 5342bc5..44244ba 100644 Binary files a/backend/db.sqlite3 and b/backend/db.sqlite3 differ diff --git a/backend/shop/__pycache__/admin.cpython-313.pyc b/backend/shop/__pycache__/admin.cpython-313.pyc index b311a91..f0692ff 100644 Binary files a/backend/shop/__pycache__/admin.cpython-313.pyc and b/backend/shop/__pycache__/admin.cpython-313.pyc differ diff --git a/backend/shop/__pycache__/models.cpython-313.pyc b/backend/shop/__pycache__/models.cpython-313.pyc index 0218948..140b8db 100644 Binary files a/backend/shop/__pycache__/models.cpython-313.pyc and b/backend/shop/__pycache__/models.cpython-313.pyc differ diff --git a/backend/shop/__pycache__/views.cpython-313.pyc b/backend/shop/__pycache__/views.cpython-313.pyc index 4eee818..794b194 100644 Binary files a/backend/shop/__pycache__/views.cpython-313.pyc and b/backend/shop/__pycache__/views.cpython-313.pyc differ