You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

765 lines
28 KiB

import json
from datetime import datetime
from decimal import Decimal
from django.contrib.auth import get_user_model
from django.db.models import Q
from rest_framework import status, views, viewsets, generics, mixins
from rest_framework.decorators import (detail_route, list_route, action,
permission_classes, authentication_classes as auth_classes)
from rest_framework.response import Response
from rest_framework.settings import api_settings
from . import ExtendedModelViewSet
from .serializers.config import ConfigSerializer
from .serializers.course import (
CategorySerializer, LikeSerializer,
CourseSerializer, CourseCreateSerializer,
CourseBulkChangeCategorySerializer,
CommentSerializer, CommentCreateSerializer,
MaterialSerializer, MaterialCreateSerializer,
LessonSerializer, LessonCreateSerializer,
LikeCreateSerializer, CourseCommentSerializer, LessonCommentSerializer,
LiveLessonCommentSerializer,)
from .serializers.content import (
BanerSerializer,
ImageSerializer, ImageCreateSerializer,
TextSerializer, TextCreateSerializer,
ImageTextSerializer, ImageTextCreateSerializer,
VideoSerializer, VideoCreateSerializer,
GallerySerializer,
GalleryImageSerializer, GalleryImageCreateSerializer,
ImageObjectSerializer, FAQSerializer,
)
from .serializers.school import (
SchoolScheduleSerializer,
LiveLessonCreateSerializer,
LiveLessonSerializer,
)
from .serializers.payment import (
AuthorBalanceSerializer, AuthorBalanceCreateSerializer,
PaymentSerializer, UserBonusSerializer, UserBonusCreateSerializer,
CoursePaymentCreateSerializer, SchoolPaymentCreateSerializer)
from .serializers.user import (
AuthorRequestSerializer,
UserSerializer, UserPhotoSerializer,
UserGallerySerializer, UserGalleryUpdateSerializer)
from .serializers.contest import (
ContestCreateSerializer, ContestSerializer, ContestWorkSerializer, ContestWorkCreateSerializer
)
from .permissions import (
IsAdmin,
IsAuthorOrAdmin, IsAuthorObjectOrAdmin,
IsTeacherOrAdmin,
)
from apps.course.models import (
Category, Course,
Comment, CourseComment, LessonComment,
Material, Lesson,
Like,
LiveLessonComment)
from apps.config.models import Config
from apps.content.models import (
Baner, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject,
Contest, ContestWork, FAQ)
from apps.payment.models import (
AuthorBalance, Payment,
CoursePayment, SchoolPayment, UserBonus,
)
from apps.school.models import SchoolSchedule, LiveLesson
from apps.user.models import AuthorRequest, EmailLog
from project.pusher import pusher
from project.sengrid import get_sendgrid_client
User = get_user_model()
class AuthorBalanceViewSet(ExtendedModelViewSet):
queryset = AuthorBalance.objects.filter(
Q(type=1) | Q(payment__status__in=Payment.PW_PAID_STATUSES),
# author__role__in=[User.AUTHOR_ROLE, User.ADMIN_ROLE, User.TEACHER_ROLE],
)
serializer_class = AuthorBalanceCreateSerializer
serializer_class_map = {
'list': AuthorBalanceSerializer,
}
permission_classes = (IsAdmin,)
filter_fields = ('author', 'status', 'type')
search_fields = (
'author__email',
'author__first_name',
'author__last_name',
)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.query_params.get('page'):
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@action(methods=['post'], detail=False, url_path='add-withdrawal')
def add_withdrawal(self, request):
author_id = request.data.get('author_id')
amount = request.data.get('amount')
card = request.data.get('card')
if not all([author_id, amount,]):
return Response(status=status.HTTP_400_BAD_REQUEST)
AuthorBalance.objects.create(
author_id=author_id,
type=AuthorBalance.OUT,
amount=Decimal(amount),
status=AuthorBalance.ACCEPTED,
card=card,
)
return Response(status=status.HTTP_200_OK)
class AuthorBalanceUsersViewSet(views.APIView):
def get(self, request):
users = AuthorBalance.objects.filter(amount__gt=0).values_list('author', flat=True)
users = User.objects.filter(id__in=users, is_active=True).order_by('first_name', 'last_name')
return Response(UserSerializer(users, many=True).data)
class BanerViewSet(ExtendedModelViewSet):
queryset = Baner.objects.all()
serializer_class = BanerSerializer
permission_classes = (IsAdmin,)
filter_fields = ('use',)
ordering_fields = ('created_at', 'update_at',)
search_fields = ('text',)
def perform_create(self, serializer):
files = dict()
for k, v in self.request.FILES.items():
if v:
files[k] = v
serializer.save(**files)
def perform_update(self, serializer):
files = dict()
for k, v in self.request.FILES.items():
if v:
files[k] = v
serializer.save(**files)
class ImageObjectViewSet(ExtendedModelViewSet):
queryset = ImageObject.objects.all()
serializer_class = ImageObjectSerializer
# FIXME
authentication_classes = []
# permission_classes = (IsAuthorOrAdmin,)
class MaterialViewSet(ExtendedModelViewSet):
queryset = Material.objects.all()
serializer_class = MaterialCreateSerializer
serializer_class_map = {
'list': MaterialSerializer,
'retrieve': MaterialSerializer,
}
search_fields = ('title', 'short_description',)
ordering_fields = ('title', 'created_at', 'update_at',)
# permission_classes = (IsAdmin,)
class LikeViewSet(ExtendedModelViewSet):
OBJ_TYPE_CONTEST_WORK = 'contest_work'
queryset = Like.objects.select_related('user').all()
serializer_class = LikeCreateSerializer
serializer_class_map = {
'list': LikeSerializer,
'retrieve': LikeSerializer,
}
search_fields = ('user__email', 'user__firstname', 'user__lastname',)
ordering_fields = ('created_at', 'update_at',)
# permission_classes = (IsAdmin,)
# FIXME
authentication_classes = []
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
obj_type = request.data.get('obj_type')
obj_id = request.data.get('obj_id')
user = serializer.validated_data.get('user')
if not user.is_active: # FIXME and user.is_authenticated):
return Response(status=status.HTTP_403_FORBIDDEN)
if obj_type == self.OBJ_TYPE_CONTEST_WORK:
contest_work = ContestWork.objects.get(pk=obj_id)
if contest_work.user == user:
return Response({'error': u'Нельзя голосовать за свою работу'}, status=status.HTTP_400_BAD_REQUEST)
if contest_work.likes.filter(user=user).exists():
return Response({'error': u'Вы уже голосовали за эту работу'}, status=status.HTTP_400_BAD_REQUEST)
if contest_work.contest.finished:
return Response({'error': u'Голосование закончено'}, status=status.HTTP_400_BAD_REQUEST)
instance = serializer.save()
if obj_type == self.OBJ_TYPE_CONTEST_WORK:
contest_work.likes.add(instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
class CategoryViewSet(ExtendedModelViewSet):
queryset = Category.objects.order_by('-id')
serializer_class = CategorySerializer
search_fields = ('title',)
ordering_fields = ('title',)
# permission_classes = (IsAdmin,)
class CourseViewSet(ExtendedModelViewSet):
queryset = Course.objects.select_related(
'author', 'category', 'cover', 'gallery',
).prefetch_related(
'likes', 'materials', 'content',
).all()
serializer_class = CourseCreateSerializer
serializer_class_map = {
'list': CourseSerializer,
'retrieve': CourseSerializer,
'draft': CourseSerializer,
'change_category_bulk': CourseBulkChangeCategorySerializer,
}
filter_fields = ('category', 'status', 'is_infinite', 'is_featured',)
search_fields = ('author__email', 'title', 'category__title',)
ordering_fields = ('id', 'title', 'created_at', 'update_at',)
# permission_classes = (IsAuthorObjectOrAdmin,)
# permission_map = {
# 'create': IsAuthorOrAdmin,
# 'delete': IsAdmin,
# }
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.query_params.get('page'):
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
else:
return Response({'results': []})
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@list_route(methods=['get'])
def draft(self, request):
drafts = Course.objects.filter(author=request.user, status=Course.DRAFT)
serializer = self.get_serializer_class()
serialized_data = serializer(instance=drafts.last())
return Response(serialized_data.data)
@list_route(methods=['patch'], url_path='change-category-bulk')
def change_category_bulk(self, request):
serializer_class = self.get_serializer_class()
serializer = serializer_class(data=request.data)
if serializer.is_valid():
old_category_id = serializer.validated_data['old_category']
new_category_id = serializer.validated_data['new_category']
try:
old_category = Category.objects.get(id=old_category_id)
except Category.DoesNotExist:
return Response(
{'success': False, 'detail': f'Category with id {old_category_id} not found'},
status=status.HTTP_400_BAD_REQUEST,
)
try:
new_category = Category.objects.get(id=new_category_id)
except Category.DoesNotExist:
return Response(
{'success': False, 'detail': f'Category with id {new_category_id} not found'},
status=status.HTTP_400_BAD_REQUEST,
)
c = Course.objects.filter(
category=old_category,
).update(
category=new_category
)
return Response({'success': True})
else:
return Response(
{'success': False},
status=status.HTTP_400_BAD_REQUEST,
)
class LessonViewSet(ExtendedModelViewSet):
queryset = Lesson.objects.select_related(
'course', 'cover'
).prefetch_related('content').all()
serializer_class = LessonCreateSerializer
serializer_class_map = {
'list': LessonSerializer,
'retrieve': LessonSerializer,
}
filter_fields = ('course',)
search_fields = ('title', 'short_description',)
ordering_fields = ('title', 'created_at', 'update_at',)
permission_classes = (IsAuthorObjectOrAdmin,)
permission_map = {
'create': IsAuthorOrAdmin,
'delete': IsAdmin,
}
class LiveLessonViewSet(ExtendedModelViewSet):
queryset = LiveLesson.objects.prefetch_related('content').all()
serializer_class = LiveLessonCreateSerializer
serializer_class_map = {
'list': LiveLessonSerializer,
'retrieve': LiveLessonSerializer,
}
search_fields = ('title', 'short_description',)
ordering_fields = ('title', 'created_at', 'update_at',)
permission_classes = (IsTeacherOrAdmin,)
permission_map = {
'delete': IsAdmin,
}
class ImageViewSet(ExtendedModelViewSet):
queryset = Image.objects.select_related(
'course', 'lesson', 'img',
).all()
serializer_class = ImageCreateSerializer
serializer_class_map = {
'list': ImageSerializer,
'retrieve': ImageSerializer,
}
search_fields = ('title',)
ordering_fields = ('title', 'created_at', 'update_at', 'position',)
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class TextViewSet(ExtendedModelViewSet):
queryset = Text.objects.select_related(
'course', 'lesson'
).all()
serializer_class = TextCreateSerializer
serializer_class_map = {
'list': TextSerializer,
'retrieve': TextSerializer,
}
search_fields = ('title',)
ordering_fields = ('title', 'created_at', 'update_at', 'position',)
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class ImageTextViewSet(ExtendedModelViewSet):
queryset = ImageText.objects.select_related(
'course', 'lesson', 'img'
).all()
serializer_class = ImageTextCreateSerializer
serializer_class_map = {
'list': ImageTextSerializer,
'retrieve': ImageTextSerializer,
}
search_fields = ('title',)
ordering_fields = ('title', 'created_at', 'update_at', 'position',)
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class VideoViewSet(ExtendedModelViewSet):
queryset = Video.objects.select_related(
'course', 'lesson'
).all()
serializer_class = VideoCreateSerializer
serializer_class_map = {
'list': VideoSerializer,
'retrieve': VideoSerializer,
}
search_fields = ('title',)
ordering_fields = ('title', 'created_at', 'update_at', 'position',)
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class GalleryViewSet(ExtendedModelViewSet):
queryset = Gallery.objects.all()
serializer_class = GallerySerializer
search_fields = ('title',)
ordering_fields = ('title', 'created_at', 'update_at',)
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class GalleryImageViewSet(ExtendedModelViewSet):
queryset = GalleryImage.objects.select_related(
'gallery', 'img',
).all()
serializer_class = GalleryImageCreateSerializer
search_fields = ('gallery__title',)
serializer_class_map = {
'list': GalleryImageSerializer,
'retrieve': GalleryImageSerializer,
}
# permission_classes = (IsAuthorOrAdmin,)
# permission_map = {
# 'delete': IsAdmin,
# }
class UserViewSet(ExtendedModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
serializer_class_map = {
'upload_photo': UserPhotoSerializer,
}
filter_fields = ('is_staff', 'is_active', 'role',
'gender', 'is_email_proved', 'fb_id',)
search_fields = ('email', 'first_name', 'last_name',
'country', 'city', 'fb_id',)
ordering_fields = ('email', 'first_name', 'last_name',
'country', 'city', 'date_joined',)
# permission_classes = (IsAdminOrIsSelf,)
# permission_map = {
# 'delete': IsAdmin,
# }
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.query_params.get('page'):
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@list_route(methods=['get'])
def me(self, request):
serializer = self.get_serializer_class()
serialized_data = serializer(instance=request.user)
return Response(serialized_data.data)
@detail_route(methods=['post'], url_path='upload-photo')
def upload_photo(self, request, pk=None):
user = self.get_object()
serializer = self.get_serializer()
serialized_data = serializer(data=request.data)
if serialized_data.is_valid():
user.photo = serialized_data['photo']
user.save()
return Response({'success': True})
else:
return Response({'success': False}, status=status.HTTP_400_BAD_REQUEST)
class UserGalleryViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
queryset = User.objects.all()
serializer_class = UserGalleryUpdateSerializer
# FIXME
authentication_classes = []
class SchoolScheduleViewSet(ExtendedModelViewSet):
queryset = SchoolSchedule.objects.all()
serializer_class = SchoolScheduleSerializer
permission_classes = (IsTeacherOrAdmin,)
class ConfigViewSet(generics.RetrieveUpdateAPIView):
queryset = Config.objects.all()
serializer_class = ConfigSerializer
permission_classes = (IsAdmin,)
def perform_update(self, serializer):
files = dict()
for k, v in self.request.FILES.items():
if v:
files[k] = v
serializer.save(**files)
def get_object(self):
return Config.load()
class CommentViewSet(ExtendedModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
permission_classes = (IsAuthorObjectOrAdmin,)
def get_queryset(self):
queryset = self.queryset
is_deactivated = self.request.query_params.get('is_deactivated', '0')
if is_deactivated == '0':
queryset = queryset.filter(level=0)
elif is_deactivated == '1':
queryset = queryset.filter(deactivated_at__isnull=True)
elif is_deactivated == '2':
queryset = queryset.filter(deactivated_at__isnull=False)
return queryset
class ObjectCommentsViewSet(ExtendedModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentCreateSerializer
ordering_fields = ('update_at', )
authentication_classes = []
def get_queryset(self):
queryset = self.queryset
obj_type = self.request.query_params.get('obj_type')
obj_id = self.request.query_params.get('obj_id')
is_deactivated = self.request.query_params.get('is_deactivated')
if obj_type == Comment.OBJ_TYPE_COURSE:
queryset = CourseComment.objects.filter(course=obj_id)
elif obj_type == Comment.OBJ_TYPE_LESSON:
queryset = LessonComment.objects.filter(lesson=obj_id)
elif obj_type == Comment.OBJ_TYPE_LIVE_LESSON:
queryset = LiveLessonComment.objects.filter(live_lesson=obj_id)
if is_deactivated == '0':
queryset = queryset.filter(level=0)
elif is_deactivated == '1':
queryset = queryset.filter(deactivated_at__isnull=True)
elif is_deactivated == '2':
queryset = queryset.filter(deactivated_at__isnull=False)
return queryset
def get_serializer_class(self):
if self.request.method == 'POST':
return CommentCreateSerializer
obj_type = self.request.query_params.get('obj_type')
serializer_class = CommentSerializer
if obj_type == Comment.OBJ_TYPE_COURSE:
serializer_class = CourseCommentSerializer
elif obj_type == Comment.OBJ_TYPE_LESSON:
serializer_class = LessonCommentSerializer
elif obj_type == Comment.OBJ_TYPE_LIVE_LESSON:
serializer_class = LiveLessonCommentSerializer
return serializer_class
def perform_create(self, serializer):
obj_type = self.request.data.get('obj_type')
obj_id = self.request.data.get('obj_id')
serializer.save()
try:
pusher().trigger(f'comments_{obj_type}_{obj_id}', 'add', serializer.data)
except Exception as e:
print(e)
@permission_classes((IsAuthorObjectOrAdmin,))
def destroy(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
def perform_destroy(self, instance):
obj_type = None
obj_id = None
if isinstance(instance, LessonComment):
obj_type = Comment.OBJ_TYPE_LESSON
obj_id = instance.lesson_id
elif isinstance(instance, CourseComment):
obj_type = Comment.OBJ_TYPE_COURSE
obj_id = instance.course_id
elif isinstance(instance, LiveLessonComment):
obj_type = Comment.OBJ_TYPE_LIVE_LESSON
obj_id = instance.live_lesson_id
serializer = self.get_serializer(instance)
try:
pusher().trigger(f'comments_{obj_type}_{obj_id}', 'delete', serializer.data)
except Exception as e:
print(e)
instance.delete()
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()).filter(parent__isnull=True)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class AuthorRequestViewSet(ExtendedModelViewSet):
queryset = AuthorRequest.objects.all()
serializer_class = AuthorRequestSerializer
permission_classes = (IsAdmin,)
filter_fields = ('status',)
class PaymentViewSet(viewsets.ModelViewSet):
queryset = Payment.objects.all()
serializer_class = PaymentSerializer
permission_classes = (IsAdmin,)
filter_fields = ('status', 'user',)
ordering_fields = (
'id', 'user__email',
'user__first_name', 'user__last_name',
'amount', 'created_at',
)
search_fields = ('user__email', 'user__first_name', 'user__last_name',)
def get_serializer(self, instance, *args, **kwargs):
serializer_class = self.get_serializer_class()
if 'update' in self.action:
if isinstance(instance, CoursePayment):
serializer_class = CoursePaymentCreateSerializer
elif isinstance(instance, SchoolPayment):
serializer_class = SchoolPaymentCreateSerializer
kwargs['context'] = self.get_serializer_context()
return serializer_class(instance, *args, **kwargs)
def get_queryset(self):
queryset = self.queryset
course = self.request.query_params.get('course')
weekdays = self.request.query_params.getlist('weekdays[]')
if course:
queryset = CoursePayment.objects.filter(course=course)
if weekdays:
queryset = SchoolPayment.objects.filter(weekdays__overlap=weekdays)
return queryset.filter(status__isnull=False).order_by('-created_at')
@action(methods=['get'], detail=False, url_path='calc-amount', authentication_classes=[], permission_classes=[])
def calc_amount(self, request, pk=None):
user = request.query_params.get('user')
course = request.query_params.get('course')
weekdays = request.query_params.getlist('weekdays[]')
date_start = request.query_params.get('date_start')
user = user and User.objects.get(pk=user)
course = course and Course.objects.get(pk=course)
date_start = date_start and datetime.strptime(date_start, '%Y-%m-%d')
return Response(Payment.calc_amount(user=user, course=course, date_start=date_start, weekdays=weekdays))
class ContestViewSet(ExtendedModelViewSet):
queryset = Contest.objects.all()
serializer_class = ContestCreateSerializer
serializer_class_map = {
'list': ContestSerializer,
'retrieve': ContestSerializer,
}
filter_fields = ('active',)
search_fields = ('description', 'title', 'slug',)
ordering_fields = ('id', 'title', 'active', 'date_start', 'date_end',)
permission_classes = (IsAdmin,)
class ContestWorkViewSet(ExtendedModelViewSet):
queryset = ContestWork.objects.all()
serializer_class = ContestWorkCreateSerializer
serializer_class_map = {
'list': ContestWorkSerializer,
'retrieve': ContestWorkSerializer,
}
filter_fields = ('contest',)
# FIXME
authentication_classes = []
def create(self, request, *args, **kwargs):
# FIXME
user = User.objects.get(pk=request.data.get('user'))
if ContestWork.objects.filter(user=user).exists():
return Response(status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
class CaptureEmail(views.APIView):
authentication_classes = ()
def post(self, request):
list_id = None
list_name = 'captured-emails'
email = request.data.get('email')
sg = get_sendgrid_client()
if not email:
return Response({'error': 'No email'}, status=status.HTTP_400_BAD_REQUEST)
EmailLog.objects.create(email=email, source=EmailLog.SOURCE_TRIAL_LESSON)
# берем все списки
response = sg.client.contactdb.lists.get()
if response.status_code != 200:
return Response({'error': 'Cannot get list of lists'}, status=status.HTTP_400_BAD_REQUEST)
# ищем нужный список
for sg_list in response.to_dict.get('lists'):
if sg_list.get('name') == list_name:
list_id = sg_list.get('id')
break
# не нашли - создаем
if not list_id:
response = sg.client.contactdb.lists.post(request_body={'name': list_name})
if response.status_code != 201:
return Response({'error': 'List was not created'}, status=status.HTTP_400_BAD_REQUEST)
list_id = response.to_dict.get('id')
# добавляем получателя
response = sg.client.contactdb.recipients.patch(request_body=[{
'email': email,
}])
if response.status_code != 201 or not response.to_dict.get('persisted_recipients'):
return Response({'error': 'Cannot update recipients'}, status=status.HTTP_400_BAD_REQUEST)
recipient_id = response.to_dict.get('persisted_recipients')[0]
# добавляем получателя в отдельный список
response = sg.client.contactdb.lists._(list_id).recipients._(recipient_id).post()
if response.status_code != 201:
return Response({'error': 'Cannot add recipient to list'}, status=status.HTTP_400_BAD_REQUEST)
return Response({'status': 'ok'})
class FAQViewSet(ExtendedModelViewSet):
queryset = FAQ.objects.all()
serializer_class = FAQSerializer
class BonusesViewSet(ExtendedModelViewSet):
queryset = UserBonus.objects.all()
serializer_class = UserBonusCreateSerializer
serializer_class_map = {
'list': UserBonusSerializer,
}
permission_classes = (IsAdmin,)
filter_fields = ('user', 'referral', 'payment', 'is_service', 'action_name')
search_fields = (
'action_name',
'user__email',
'user__first_name',
'user__last_name',
'referral__referral__email',
'referral__referral__first_name',
'referral__referral__last_name',
)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.query_params.get('page'):
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)