|
@@ -0,0 +1,117 @@
|
|
|
+from rest_framework import viewsets, status, permissions
|
|
|
+from rest_framework.decorators import action
|
|
|
+from rest_framework.response import Response
|
|
|
+from rest_framework.exceptions import MethodNotAllowed # <<<< 新增导入
|
|
|
+# from django.shortcuts import get_object_or_404
|
|
|
+
|
|
|
+from .models import Group, Membership, Post
|
|
|
+from .serializers import (
|
|
|
+ GroupSerializer,
|
|
|
+ # MembershipSerializer,
|
|
|
+ PostSerializer
|
|
|
+)
|
|
|
+from .permissions import IsAuthorOrReadOnly # 从自定义权限文件导入
|
|
|
+
|
|
|
+class GroupViewSet(viewsets.ModelViewSet):
|
|
|
+ queryset = Group.objects.all().order_by('-created_at')
|
|
|
+ serializer_class = GroupSerializer
|
|
|
+
|
|
|
+ def get_permissions(self):
|
|
|
+ if self.action in ['list', 'retrieve']:
|
|
|
+ permission_classes = [permissions.AllowAny]
|
|
|
+ elif self.action in ['list_group_posts', 'create_group_post', 'join_group', 'leave_group', 'my_groups']:
|
|
|
+ permission_classes = [permissions.IsAuthenticated]
|
|
|
+ else: # create, update, partial_update, destroy (for groups)
|
|
|
+ permission_classes = [permissions.IsAuthenticated]
|
|
|
+ return [permission() for permission in permission_classes]
|
|
|
+
|
|
|
+ def perform_create(self, serializer):
|
|
|
+ group = serializer.save(creator=self.request.user)
|
|
|
+ Membership.objects.create(user=self.request.user, group=group)
|
|
|
+
|
|
|
+ @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
|
|
|
+ def join_group(self, request, pk=None):
|
|
|
+ group = self.get_object()
|
|
|
+ user = request.user
|
|
|
+ if Membership.objects.filter(user=user, group=group).exists():
|
|
|
+ return Response({'detail': '您已经是该小组成员。'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
+ Membership.objects.create(user=user, group=group)
|
|
|
+ return Response({'detail': '成功加入小组。'}, status=status.HTTP_200_OK)
|
|
|
+
|
|
|
+ @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
|
|
|
+ def leave_group(self, request, pk=None):
|
|
|
+ group = self.get_object()
|
|
|
+ user = request.user
|
|
|
+ try:
|
|
|
+ membership = Membership.objects.get(user=user, group=group)
|
|
|
+ membership.delete()
|
|
|
+ return Response({'detail': '成功退出小组。'}, status=status.HTTP_200_OK)
|
|
|
+ except Membership.DoesNotExist:
|
|
|
+ return Response({'detail': '您不是该小组成员。'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
+
|
|
|
+ @action(detail=False, methods=['get'], permission_classes=[permissions.IsAuthenticated], url_path='my-groups')
|
|
|
+ def my_groups(self, request):
|
|
|
+ user = request.user
|
|
|
+ memberships = Membership.objects.filter(user=user).select_related('group')
|
|
|
+ groups = [membership.group for membership in memberships]
|
|
|
+ page = self.paginate_queryset(groups)
|
|
|
+ if page is not None:
|
|
|
+ serializer = self.get_serializer(page, many=True, context={'request': request})
|
|
|
+ return self.get_paginated_response(serializer.data)
|
|
|
+ serializer = self.get_serializer(groups, many=True, context={'request': request})
|
|
|
+ return Response(serializer.data)
|
|
|
+
|
|
|
+ @action(detail=True, methods=['get'], url_path='posts', url_name='group-posts-list')
|
|
|
+ def list_group_posts(self, request, pk=None):
|
|
|
+ group = self.get_object()
|
|
|
+ posts_queryset = Post.objects.filter(group=group).order_by('-created_at')
|
|
|
+ page = self.paginate_queryset(posts_queryset)
|
|
|
+ if page is not None:
|
|
|
+ serializer = PostSerializer(page, many=True, context={'request': request})
|
|
|
+ return self.get_paginated_response(serializer.data)
|
|
|
+ serializer = PostSerializer(posts_queryset, many=True, context={'request': request})
|
|
|
+ return Response(serializer.data)
|
|
|
+
|
|
|
+ @action(detail=True, methods=['post'], url_path='create-post', url_name='group-post-create')
|
|
|
+ def create_group_post(self, request, pk=None):
|
|
|
+ group = self.get_object()
|
|
|
+ serializer = PostSerializer(data=request.data, context={'request': request})
|
|
|
+ if serializer.is_valid():
|
|
|
+ serializer.save(author=request.user, group=group)
|
|
|
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
|
|
|
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
+
|
|
|
+
|
|
|
+class PostViewSet(viewsets.ModelViewSet):
|
|
|
+ queryset = Post.objects.all().select_related('author', 'group').order_by('-created_at')
|
|
|
+ serializer_class = PostSerializer
|
|
|
+
|
|
|
+ def get_permissions(self):
|
|
|
+ if self.action in ['list', 'retrieve']:
|
|
|
+ permission_classes = [permissions.IsAuthenticated] # 或者 IsAuthenticatedOrReadOnly
|
|
|
+ elif self.action in ['update', 'partial_update', 'destroy']:
|
|
|
+ permission_classes = [permissions.IsAuthenticated, IsAuthorOrReadOnly]
|
|
|
+ elif self.action == 'create':
|
|
|
+ # 即使是Admin,我们也希望通过小组接口创建帖子,以确保group关联正确
|
|
|
+ # 所以这里可以直接禁止,或者只允许特定调试场景
|
|
|
+ permission_classes = [permissions.IsAdminUser] # 示例:只允许Admin(但会被perform_create阻止)
|
|
|
+ else:
|
|
|
+ permission_classes = [permissions.IsAuthenticated]
|
|
|
+ return [permission() for permission in permission_classes]
|
|
|
+
|
|
|
+ def perform_create(self, serializer): # <<<< 修改这里
|
|
|
+ """
|
|
|
+ 通过此独立ViewSet创建帖子是不推荐的。
|
|
|
+ 应通过 /api/v1/groups/<group_pk>/create-post/ 创建。
|
|
|
+ """
|
|
|
+ raise MethodNotAllowed(
|
|
|
+ method=self.request.method,
|
|
|
+ detail="不推荐通过此接口创建帖子。请通过小组接口 /api/v1/groups/<group_pk>/create-post/ 创建。"
|
|
|
+ )
|
|
|
+
|
|
|
+ # perform_update 和 perform_destroy 由 IsAuthorOrReadOnly 权限类控制,无需显式覆盖默认行为
|
|
|
+ # def perform_update(self, serializer):
|
|
|
+ # serializer.save() # DRF默认行为
|
|
|
+
|
|
|
+ # def perform_destroy(self, instance):
|
|
|
+ # instance.delete() # DRF默认行为
|