views.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. from django.db.models import Count
  2. from django.utils import timezone
  3. from drf_yasg import openapi
  4. from drf_yasg.utils import swagger_auto_schema
  5. from rest_framework import status
  6. from rest_framework.generics import GenericAPIView
  7. from rest_framework.mixins import UpdateModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, ListModelMixin
  8. from rest_framework.response import Response
  9. from rest_framework.views import APIView
  10. from .querysets import ALL_UBC_QUERYSET
  11. from .serializers import UsersBooksCollectionsSerializer, UsersBooksCollectionsPostSerializer
  12. from api.permissions import AllowAny, IsAuthenticated, IsAdmin
  13. from content.models import UsersBooksCollections, Collection, Book, Author, Genre
  14. from ..author.serializers import AuthorSerializer
  15. from ..genre.serializers import GenreSerializer
  16. from ..permissions import IsStaffOrAdmin
  17. # region base
  18. class UBCAPIView(GenericAPIView):
  19. queryset = ALL_UBC_QUERYSET
  20. serializer_class = UsersBooksCollectionsSerializer
  21. permission_classes = [AllowAny]
  22. ordering_fields = ["created_at"]
  23. ordering = ["-created_at"]
  24. class UBCMEAPIView(UBCAPIView):
  25. permission_classes = [IsAuthenticated,]
  26. def get_queryset(self):
  27. return ALL_UBC_QUERYSET.filter(user=self.request.user)
  28. class UBCMECOLLAPIView(UBCAPIView):
  29. permission_classes = [IsAuthenticated,]
  30. def get_queryset(self):
  31. collection_uuid = self.kwargs["collection_uuid"]
  32. return ALL_UBC_QUERYSET.filter(user=self.request.user, collection__uuid=collection_uuid)
  33. # endregion
  34. # region private
  35. class UBCListView(ListModelMixin, CreateModelMixin, UBCAPIView):
  36. permission_classes = [IsStaffOrAdmin]
  37. def get(self, request, *args, **kwargs):
  38. return self.list(request, *args, **kwargs)
  39. # endregion
  40. # region public
  41. class TopReadAPIView(APIView):
  42. permission_classes = [IsAuthenticated,]
  43. def get(self, request):
  44. collections = Collection.objects.filter(title__in=["Читаемое", "Прочитано"])
  45. books = Book.objects.filter(
  46. usersbookscollections__user=request.user,
  47. usersbookscollections__collection__in=collections
  48. ).prefetch_related('genres', 'authors')
  49. top_authors = (
  50. books.values('authors__id', 'authors__name')
  51. .annotate(read_count=Count('usersbookscollections'))
  52. .order_by('-read_count')[:3]
  53. )
  54. top_genres = (
  55. books.values('genres__id', 'genres__title')
  56. .annotate(read_count=Count('usersbookscollections'))
  57. .order_by('-read_count')[:3]
  58. )
  59. top_authors_data = [
  60. {'id': author['authors__id'], 'name': author['authors__name']}
  61. for author in top_authors
  62. ]
  63. top_genres_data = [
  64. {'id': genre['genres__id'], 'name': genre['genres__title']}
  65. for genre in top_genres
  66. ]
  67. return Response({
  68. 'top_authors': top_authors_data,
  69. 'top_genres': top_genres_data
  70. })
  71. class CheckBookInBookmarksView(APIView):
  72. permission_classes = [IsAuthenticated,]
  73. def get(self, request, book_uuid):
  74. user = request.user
  75. try:
  76. bookmark = UsersBooksCollections.objects.get(user=user, book__uuid=book_uuid, collection__title='Закладки')
  77. return Response({"exists": True}, status=status.HTTP_200_OK)
  78. except UsersBooksCollections.DoesNotExist:
  79. return Response({"exists": False}, status=status.HTTP_200_OK)
  80. class UBCMEListView(UBCMEAPIView, ListModelMixin):
  81. def get(self, request, *args, **kwargs):
  82. return self.list(request, *args, **kwargs)
  83. class UBCMECreateView(UBCMEAPIView, CreateModelMixin):
  84. serializer_class = UsersBooksCollectionsPostSerializer
  85. def post(self, request, *args, **kwargs):
  86. serializer = self.get_serializer(data=request.data)
  87. serializer.is_valid(raise_exception=True)
  88. self.perform_create(serializer)
  89. return Response(serializer.data, status=status.HTTP_201_CREATED)
  90. def perform_create(self, serializer):
  91. serializer.save(user=self.request.user)
  92. class UBCMECOLLListView(ListModelMixin, UBCMECOLLAPIView):
  93. def get(self, request, *args, **kwargs):
  94. return self.list(request, *args, **kwargs)
  95. class UBCMERetrieveUpdateDestroyView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, UBCMEAPIView):
  96. def get(self, request, *args, **kwargs):
  97. return self.retrieve(request, *args, **kwargs)
  98. def put(self, request, *args, **kwargs):
  99. return self.update(request, *args, **kwargs)
  100. def patch(self, request, *args, **kwargs):
  101. return self.partial_update(request, *args, **kwargs)
  102. def delete(self, request, *args, **kwargs):
  103. return self.destroy(request, *args, **kwargs)
  104. def perform_destroy(self, instance):
  105. instance.delete()
  106. class CountReadBooksView(APIView):
  107. permission_classes = [IsAuthenticated,]
  108. @swagger_auto_schema(
  109. manual_parameters=[
  110. openapi.Parameter(
  111. 'start_date',
  112. openapi.IN_QUERY,
  113. description="Начальная дата в формате ISO 8601 (2023-12-31T23:59:59)",
  114. type=openapi.TYPE_STRING,
  115. format=openapi.FORMAT_DATETIME,
  116. required=True
  117. ),
  118. openapi.Parameter(
  119. 'end_date',
  120. openapi.IN_QUERY,
  121. description="Конечная дата в формате ISO 8601 (2023-12-31T23:59:59)",
  122. type=openapi.TYPE_STRING,
  123. format=openapi.FORMAT_DATETIME,
  124. required=True
  125. ),
  126. ], )
  127. def get(self, request):
  128. user = request.user
  129. start_date = request.query_params.get('start_date')
  130. end_date = request.query_params.get('end_date')
  131. if not start_date or not end_date:
  132. return Response({"error": "Диапазон дат не предоставлен"}, status=status.HTTP_400_BAD_REQUEST)
  133. try:
  134. start_date = timezone.datetime.fromisoformat(start_date)
  135. end_date = timezone.datetime.fromisoformat(end_date)
  136. except ValueError:
  137. return Response({"error": "Некорректный формат переданных дат"}, status=status.HTTP_400_BAD_REQUEST)
  138. count = UsersBooksCollections.objects.filter(
  139. user=user,
  140. collection__title='Прочитано',
  141. created_at__range=(start_date, end_date)
  142. ).count()
  143. return Response({"count": count}, status=status.HTTP_200_OK)
  144. # endregion