heart
All checks were successful
Deploy to Server / deploy (push) Successful in 38s

This commit is contained in:
jeremygan2021
2026-03-02 20:28:16 +08:00
parent e306ac6f61
commit 2ef1771be0
10 changed files with 198 additions and 7 deletions

View File

@@ -0,0 +1,24 @@
# Generated by Django 6.0.1 on 2026-03-02 12:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('community', '0015_topic_status'),
('shop', '0039_vccourse_video_embed_code'),
]
operations = [
migrations.AddField(
model_name='reply',
name='likes',
field=models.ManyToManyField(blank=True, related_name='liked_replies', to='shop.wechatuser', verbose_name='点赞用户'),
),
migrations.AddField(
model_name='topic',
name='likes',
field=models.ManyToManyField(blank=True, related_name='liked_topics', to='shop.wechatuser', verbose_name='点赞用户'),
),
]

View File

@@ -143,6 +143,7 @@ class Topic(models.Model):
related_course = models.ForeignKey(VCCourse, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="关联课程")
view_count = models.IntegerField(default=0, verbose_name="浏览量")
likes = models.ManyToManyField(WeChatUser, related_name='liked_topics', blank=True, verbose_name="点赞用户")
is_pinned = models.BooleanField(default=False, verbose_name="置顶")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="发布时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
@@ -209,6 +210,7 @@ class Reply(models.Model):
content = models.TextField(verbose_name="回复内容", help_text="支持Markdown格式")
author = models.ForeignKey(WeChatUser, on_delete=models.CASCADE, related_name='replies', verbose_name="回复者")
reply_to = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='children', verbose_name="回复楼层")
likes = models.ManyToManyField(WeChatUser, related_name='liked_replies', blank=True, verbose_name="点赞用户")
is_pinned = models.BooleanField(default=False, verbose_name="置顶")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="回复时间")

View File

@@ -88,12 +88,23 @@ class ReplySerializer(serializers.ModelSerializer):
write_only=True,
required=False
)
like_count = serializers.IntegerField(source='likes.count', read_only=True)
is_liked = serializers.SerializerMethodField()
class Meta:
model = Reply
fields = ['id', 'topic', 'content', 'author', 'author_info', 'reply_to', 'media', 'created_at', 'media_ids', 'is_pinned']
fields = ['id', 'topic', 'content', 'author', 'author_info', 'reply_to', 'media', 'created_at', 'media_ids', 'is_pinned', 'like_count', 'is_liked']
read_only_fields = ['author', 'created_at']
def get_is_liked(self, obj):
request = self.context.get('request')
if not request:
return False
user = get_current_wechat_user(request)
if user:
return obj.likes.filter(id=user.id).exists()
return False
def create(self, validated_data):
media_ids = validated_data.pop('media_ids', [])
reply = super().create(validated_data)
@@ -106,6 +117,8 @@ class TopicSerializer(serializers.ModelSerializer):
replies = ReplySerializer(many=True, read_only=True)
media = TopicMediaSerializer(many=True, read_only=True)
is_verified_owner = serializers.BooleanField(read_only=True)
like_count = serializers.IntegerField(source='likes.count', read_only=True)
is_liked = serializers.SerializerMethodField()
product_info = ESP32ConfigSerializer(source='related_product', read_only=True)
service_info = ServiceSerializer(source='related_service', read_only=True)
@@ -125,10 +138,20 @@ class TopicSerializer(serializers.ModelSerializer):
'related_service', 'service_info',
'related_course', 'course_info',
'view_count', 'is_pinned', 'created_at', 'updated_at',
'is_verified_owner', 'replies', 'media', 'media_ids'
'is_verified_owner', 'replies', 'media', 'media_ids',
'like_count', 'is_liked'
]
read_only_fields = ['author', 'view_count', 'created_at', 'updated_at', 'is_verified_owner', 'status']
def get_is_liked(self, obj):
request = self.context.get('request')
if not request:
return False
user = get_current_wechat_user(request)
if user:
return obj.likes.filter(id=user.id).exists()
return False
def create(self, validated_data):
media_ids = validated_data.pop('media_ids', [])
topic = super().create(validated_data)

View File

@@ -284,6 +284,22 @@ class TopicViewSet(viewsets.ModelViewSet):
return Response({'error': '请先登录'}, status=401)
return super().create(request, *args, **kwargs)
@action(detail=True, methods=['post'])
def like(self, request, pk=None):
obj = self.get_object()
user = get_current_wechat_user(request)
if not user:
return Response({'error': '请先登录'}, status=401)
if obj.likes.filter(id=user.id).exists():
obj.likes.remove(user)
liked = False
else:
obj.likes.add(user)
liked = True
return Response({'liked': liked, 'count': obj.likes.count()})
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.view_count += 1
@@ -310,6 +326,22 @@ class ReplyViewSet(viewsets.ModelViewSet):
return Response({'error': '请先登录'}, status=401)
return super().create(request, *args, **kwargs)
@action(detail=True, methods=['post'])
def like(self, request, pk=None):
obj = self.get_object()
user = get_current_wechat_user(request)
if not user:
return Response({'error': '请先登录'}, status=401)
if obj.likes.filter(id=user.id).exists():
obj.likes.remove(user)
liked = False
else:
obj.likes.add(user)
liked = True
return Response({'liked': liked, 'count': obj.likes.count()})
import requests
class TopicMediaViewSet(viewsets.ViewSet):