views.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from rest_framework import viewsets, status, permissions
  2. from rest_framework.decorators import action
  3. from rest_framework.response import Response
  4. from rest_framework.exceptions import MethodNotAllowed # <<<< 新增导入
  5. # from django.shortcuts import get_object_or_404
  6. from .models import Group, Membership, Post
  7. from .serializers import (
  8. GroupSerializer,
  9. # MembershipSerializer,
  10. PostSerializer
  11. )
  12. from .permissions import IsAuthorOrReadOnly # 从自定义权限文件导入
  13. class GroupViewSet(viewsets.ModelViewSet):
  14. queryset = Group.objects.all().order_by('-created_at')
  15. serializer_class = GroupSerializer
  16. def get_permissions(self):
  17. if self.action in ['list', 'retrieve']:
  18. permission_classes = [permissions.AllowAny]
  19. elif self.action in ['list_group_posts', 'create_group_post', 'join_group', 'leave_group', 'my_groups']:
  20. permission_classes = [permissions.IsAuthenticated]
  21. else: # create, update, partial_update, destroy (for groups)
  22. permission_classes = [permissions.IsAuthenticated]
  23. return [permission() for permission in permission_classes]
  24. def perform_create(self, serializer):
  25. group = serializer.save(creator=self.request.user)
  26. Membership.objects.create(user=self.request.user, group=group)
  27. @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
  28. def join_group(self, request, pk=None):
  29. group = self.get_object()
  30. user = request.user
  31. if Membership.objects.filter(user=user, group=group).exists():
  32. return Response({'detail': '您已经是该小组成员。'}, status=status.HTTP_400_BAD_REQUEST)
  33. Membership.objects.create(user=user, group=group)
  34. return Response({'detail': '成功加入小组。'}, status=status.HTTP_200_OK)
  35. @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
  36. def leave_group(self, request, pk=None):
  37. group = self.get_object()
  38. user = request.user
  39. try:
  40. membership = Membership.objects.get(user=user, group=group)
  41. membership.delete()
  42. return Response({'detail': '成功退出小组。'}, status=status.HTTP_200_OK)
  43. except Membership.DoesNotExist:
  44. return Response({'detail': '您不是该小组成员。'}, status=status.HTTP_400_BAD_REQUEST)
  45. @action(detail=False, methods=['get'], permission_classes=[permissions.IsAuthenticated], url_path='my-groups')
  46. def my_groups(self, request):
  47. user = request.user
  48. memberships = Membership.objects.filter(user=user).select_related('group')
  49. groups = [membership.group for membership in memberships]
  50. page = self.paginate_queryset(groups)
  51. if page is not None:
  52. serializer = self.get_serializer(page, many=True, context={'request': request})
  53. return self.get_paginated_response(serializer.data)
  54. serializer = self.get_serializer(groups, many=True, context={'request': request})
  55. return Response(serializer.data)
  56. @action(detail=True, methods=['get'], url_path='posts', url_name='group-posts-list')
  57. def list_group_posts(self, request, pk=None):
  58. group = self.get_object()
  59. posts_queryset = Post.objects.filter(group=group).order_by('-created_at')
  60. page = self.paginate_queryset(posts_queryset)
  61. if page is not None:
  62. serializer = PostSerializer(page, many=True, context={'request': request})
  63. return self.get_paginated_response(serializer.data)
  64. serializer = PostSerializer(posts_queryset, many=True, context={'request': request})
  65. return Response(serializer.data)
  66. @action(detail=True, methods=['post'], url_path='create-post', url_name='group-post-create')
  67. def create_group_post(self, request, pk=None):
  68. group = self.get_object()
  69. serializer = PostSerializer(data=request.data, context={'request': request})
  70. if serializer.is_valid():
  71. serializer.save(author=request.user, group=group)
  72. return Response(serializer.data, status=status.HTTP_201_CREATED)
  73. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  74. class PostViewSet(viewsets.ModelViewSet):
  75. queryset = Post.objects.all().select_related('author', 'group').order_by('-created_at')
  76. serializer_class = PostSerializer
  77. def get_permissions(self):
  78. if self.action in ['list', 'retrieve']:
  79. permission_classes = [permissions.IsAuthenticated] # 或者 IsAuthenticatedOrReadOnly
  80. elif self.action in ['update', 'partial_update', 'destroy']:
  81. permission_classes = [permissions.IsAuthenticated, IsAuthorOrReadOnly]
  82. elif self.action == 'create':
  83. # 即使是Admin,我们也希望通过小组接口创建帖子,以确保group关联正确
  84. # 所以这里可以直接禁止,或者只允许特定调试场景
  85. permission_classes = [permissions.IsAdminUser] # 示例:只允许Admin(但会被perform_create阻止)
  86. else:
  87. permission_classes = [permissions.IsAuthenticated]
  88. return [permission() for permission in permission_classes]
  89. def perform_create(self, serializer): # <<<< 修改这里
  90. """
  91. 通过此独立ViewSet创建帖子是不推荐的。
  92. 应通过 /api/v1/groups/<group_pk>/create-post/ 创建。
  93. """
  94. raise MethodNotAllowed(
  95. method=self.request.method,
  96. detail="不推荐通过此接口创建帖子。请通过小组接口 /api/v1/groups/<group_pk>/create-post/ 创建。"
  97. )
  98. # perform_update 和 perform_destroy 由 IsAuthorOrReadOnly 权限类控制,无需显式覆盖默认行为
  99. # def perform_update(self, serializer):
  100. # serializer.save() # DRF默认行为
  101. # def perform_destroy(self, instance):
  102. # instance.delete() # DRF默认行为