serializers.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. from rest_framework import serializers
  2. from .models import Group, Membership, Post, Comment, PostLike # <<<< 导入 PostLike 模型
  3. from accounts.models import CustomUser, InterestTag
  4. from accounts.serializers import InterestTagSerializer as AccountsInterestTagSerializer
  5. # --- Minimal Serializers for nested representations ---
  6. class MinimalUserSerializer(serializers.ModelSerializer):
  7. avatar_url = serializers.SerializerMethodField()
  8. class Meta:
  9. model = CustomUser
  10. fields = ('id', 'nickname', 'avatar_url')
  11. def get_avatar_url(self, obj):
  12. request = self.context.get('request')
  13. if obj.avatar and hasattr(obj.avatar, 'url'):
  14. if request is not None:
  15. return request.build_absolute_uri(obj.avatar.url)
  16. return obj.avatar.url
  17. return None
  18. class MinimalGroupSerializer(serializers.ModelSerializer):
  19. class Meta:
  20. model = Group
  21. fields = ('id', 'name')
  22. # --- Main Serializers ---
  23. class GroupSerializer(serializers.ModelSerializer):
  24. creator = MinimalUserSerializer(read_only=True)
  25. members_count = serializers.IntegerField(source='members.count', read_only=True)
  26. tags = serializers.PrimaryKeyRelatedField(
  27. queryset=InterestTag.objects.all(),
  28. many=True,
  29. required=False,
  30. allow_empty=True
  31. )
  32. tags_details = AccountsInterestTagSerializer(source='tags', many=True, read_only=True)
  33. cover_image = serializers.ImageField(max_length=None, use_url=True, required=False, allow_null=True)
  34. cover_image_url = serializers.SerializerMethodField(read_only=True)
  35. class Meta:
  36. model = Group
  37. fields = (
  38. 'id', 'name', 'description',
  39. 'cover_image', 'cover_image_url',
  40. 'creator', 'members_count',
  41. 'tags', 'tags_details',
  42. 'created_at', 'updated_at'
  43. )
  44. read_only_fields = ('id', 'created_at', 'updated_at', 'creator', 'members_count', 'tags_details', 'cover_image_url')
  45. def get_cover_image_url(self, obj):
  46. request = self.context.get('request')
  47. if obj.cover_image and hasattr(obj.cover_image, 'url'):
  48. if request is not None:
  49. return request.build_absolute_uri(obj.cover_image.url)
  50. return obj.cover_image.url
  51. return None
  52. def create(self, validated_data):
  53. tags_data = validated_data.pop('tags', None)
  54. group = super().create(validated_data)
  55. if tags_data is not None:
  56. group.tags.set(tags_data)
  57. return group
  58. def update(self, instance, validated_data):
  59. tags_data = validated_data.pop('tags', None)
  60. instance = super().update(instance, validated_data)
  61. if tags_data is not None:
  62. instance.tags.set(tags_data)
  63. return instance
  64. class MembershipSerializer(serializers.ModelSerializer):
  65. user = MinimalUserSerializer(read_only=True)
  66. group_id = serializers.IntegerField(source='group.id', read_only=True)
  67. group_name = serializers.CharField(source='group.name', read_only=True)
  68. class Meta:
  69. model = Membership
  70. fields = ('id', 'user', 'group_id', 'group_name', 'date_joined')
  71. read_only_fields = ('id', 'user', 'group_id', 'group_name', 'date_joined')
  72. class PostSerializer(serializers.ModelSerializer): # <<<< 修改 PostSerializer
  73. author = MinimalUserSerializer(read_only=True)
  74. group = MinimalGroupSerializer(read_only=True)
  75. # 新增:点赞相关字段
  76. likes_count = serializers.SerializerMethodField(read_only=True)
  77. is_liked_by_current_user = serializers.SerializerMethodField(read_only=True)
  78. class Meta:
  79. model = Post
  80. fields = (
  81. 'id',
  82. 'group',
  83. 'author',
  84. 'title',
  85. 'content',
  86. 'created_at',
  87. 'updated_at',
  88. 'likes_count', # 新增
  89. 'is_liked_by_current_user', # 新增
  90. )
  91. read_only_fields = (
  92. 'id', 'author', 'group', 'created_at', 'updated_at',
  93. 'likes_count', 'is_liked_by_current_user' # 新增的也设为只读
  94. )
  95. def get_likes_count(self, obj: Post) -> int: # obj 是 Post 实例
  96. """获取帖子的总点赞数。"""
  97. return obj.likes.count() # obj.likes 是 PostLike 的 related_name
  98. def get_is_liked_by_current_user(self, obj: Post) -> bool: # obj 是 Post 实例
  99. """检查当前用户是否已点赞该帖子。"""
  100. request = self.context.get('request')
  101. if not request or not request.user or not request.user.is_authenticated:
  102. return False # 未登录用户或匿名用户视为未点赞
  103. # 检查是否存在当前用户对该帖子的点赞记录
  104. return PostLike.objects.filter(post=obj, user=request.user).exists()
  105. class CommentSerializer(serializers.ModelSerializer):
  106. author = MinimalUserSerializer(read_only=True)
  107. post_id_display = serializers.IntegerField(source='post.id', read_only=True)
  108. post_title_display = serializers.CharField(source='post.title', read_only=True, allow_null=True)
  109. class Meta:
  110. model = Comment
  111. fields = (
  112. 'id',
  113. 'post_id_display',
  114. 'post_title_display',
  115. 'author',
  116. 'content',
  117. 'created_at',
  118. 'updated_at',
  119. )
  120. read_only_fields = ('id', 'author', 'post_id_display', 'post_title_display', 'created_at', 'updated_at')
  121. class PostLikeSerializer(serializers.ModelSerializer): # <<<< (可选) 新增 PostLikeSerializer
  122. user = MinimalUserSerializer(read_only=True)
  123. # 如果需要在点赞详情中显示帖子信息,可以添加 post 字段
  124. # post = MinimalPostSerializer(read_only=True) # 假设有 MinimalPostSerializer
  125. post_id = serializers.IntegerField(source='post.id', read_only=True)
  126. class Meta:
  127. model = PostLike
  128. fields = ('id', 'user', 'post_id', 'created_at')
  129. read_only_fields = ('id', 'user', 'post_id', 'created_at')