from django.contrib.auth import get_user_model from django.db.models import Count, Q from django.shortcuts import get_object_or_404 from rest_framework.filters import SearchFilter from rest_framework.generics import ListAPIView, RetrieveAPIView from rest_framework.permissions import AllowAny from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema from apps.course.models import Course from apps.course.serializers import ( CourseListSerializer, ProfessorDetailSerializer, ProfessorListSerializer, ) UserModel = get_user_model() class ProfessorListAPIView(ListAPIView): permission_classes = [AllowAny] serializer_class = ProfessorListSerializer filter_backends = [SearchFilter] search_fields = ['fullname', 'email'] @swagger_auto_schema( operation_description='دریافت فهرست استادها به همراه تعداد دوره‌ها و درس‌های فعال هر استاد.', responses={ 200: openapi.Response( description='فهرست صفحه‌بندی‌شده‌ی استادها.', schema=ProfessorListSerializer(many=True), examples={ 'application/json': { 'count': 1, 'next': None, 'previous': None, 'results': [ { 'id': 7, 'slug': 'dr-rahimi', 'fullname': 'دکتر رحیمی', 'experience_years': 10, 'course_count': 4, 'lesson_count': 56, } ], } }, ) }, ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): return ( UserModel.objects.filter(user_type=UserModel.UserType.PROFESSOR) .annotate( course_count=Count('courses', distinct=True), lesson_count=Count('courses__lessons', filter=Q(courses__lessons__is_active=True), distinct=True), ) .order_by('fullname') ) class ProfessorDetailAPIView(RetrieveAPIView): permission_classes = [AllowAny] serializer_class = ProfessorDetailSerializer lookup_field = 'slug' @swagger_auto_schema( operation_description='دریافت جزئیات یک استاد بر اساس اسلاگ.', responses={ 200: openapi.Response( description='اطلاعات کامل استاد.', schema=ProfessorDetailSerializer(), examples={ 'application/json': { 'id': 7, 'device_id': 'abc-123', 'fcm': None, 'fullname': 'دکتر رحیمی', 'avatar': None, 'email': 'rahimi@example.com', 'phone_number': '+989121234567', 'password': None, 'info': 'متخصص فیزیک پزشکی.', 'skill': 'فیزیک، تدریس آنلاین', 'city': 'تهران', 'country': 'ایران', 'birthdate': '1985-04-12', 'gender': 'male', 'slug': 'dr-rahimi', 'experience_years': 10, 'course_count': 4, 'lesson_count': 56, } }, ) }, ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): return UserModel.objects.filter(user_type=UserModel.UserType.PROFESSOR).annotate( course_count=Count('courses', distinct=True), lesson_count=Count('courses__lessons', filter=Q(courses__lessons__is_active=True), distinct=True), ) class ProfessorCourseListAPIView(ListAPIView): permission_classes = [AllowAny] serializer_class = CourseListSerializer filter_backends = [SearchFilter] search_fields = ['title', 'category__name'] @swagger_auto_schema( operation_description='دریافت فهرست دوره‌های فعال یک استاد مشخص‌شده با اسلاگ.', responses={ 200: openapi.Response( description='فهرست صفحه‌بندی‌شده‌ی دوره‌ها.', schema=CourseListSerializer(many=True), examples={ 'application/json': { 'count': 1, 'next': None, 'previous': None, 'results': [ { 'id': 42, 'title': 'فیزیک پایه', 'slug': 'basic-physics', 'participant_count': 150, 'category': { 'name': 'علوم پایه', 'slug': 'basic-science', 'course_count': 12, }, 'thumbnail': None, 'is_online': True, 'online_link': 'https://example.com/live/basic-physics', 'level': 'beginner', 'duration': '12h', 'lessons_count': 24, 'short_description': 'مروری بر مفاهیم پایه فیزیک.', 'status': 'published', 'is_free': False, 'price': '250000', 'discount_percentage': 20, 'final_price': '200000', } ], } }, ) }, ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): slug = self.kwargs.get('slug') professor = get_object_or_404(UserModel.objects.filter(user_type=UserModel.UserType.PROFESSOR, slug=slug)) return Course.objects.select_related('category', 'professor').prefetch_related( 'lessons__lesson', 'lessons__completions', 'participants__student', ).exclude(status=Course.StatusChoices.INACTIVE).filter(professor=professor)