Browse Source

dashboard quiz page endpoints added

created views and serializers specially for dashboard , crud operations on quizez , filtering and ...
master
Mohsen Taba 2 months ago
parent
commit
ae859d3810
  1. 119
      apps/quiz/serializers/admin.py
  2. 12
      apps/quiz/urls.py
  3. 1
      apps/quiz/views/__init__.py
  4. 156
      apps/quiz/views/admin.py

119
apps/quiz/serializers/admin.py

@ -0,0 +1,119 @@
from rest_framework import serializers
from apps.quiz.models import Quiz, Question, QuizParticipant
from apps.course.models import Course, CourseLesson
from apps.account.models import User
class AdminCourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = ['id', 'title']
class AdminCourseLessonSerializer(serializers.ModelSerializer):
title = serializers.SerializerMethodField()
class Meta:
model = CourseLesson
fields = ['id', 'title']
def get_title(self, obj):
if obj.title:
return obj.title
if obj.lesson:
return obj.lesson.title
return f"Lesson {obj.id}"
class AdminQuizListSerializer(serializers.ModelSerializer):
questions_count = serializers.SerializerMethodField()
participants_count = serializers.SerializerMethodField()
course_title = serializers.SerializerMethodField()
lesson_title = serializers.SerializerMethodField()
class Meta:
model = Quiz
fields = [
'id',
'title',
'description',
'each_question_timing',
'status',
'course',
'course_title',
'lesson',
'lesson_title',
'questions_count',
'participants_count'
]
def get_questions_count(self, obj):
return obj.questions.count()
def get_participants_count(self, obj):
return obj.participants.count()
def get_course_title(self, obj):
return obj.course.title if obj.course else None
def get_lesson_title(self, obj):
if not obj.lesson:
return None
return obj.lesson.title or (obj.lesson.lesson.title if obj.lesson.lesson else None)
class AdminQuizDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Quiz
fields = [
'id',
'title',
'description',
'each_question_timing',
'status',
'course',
'lesson'
]
read_only_fields = ['course'] # Set automatically on save based on lesson.course
class AdminQuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = [
'id',
'quiz',
'question',
'option1',
'option2',
'option3',
'option4',
'correct_answer',
'priority'
]
class AdminQuizParticipantSerializer(serializers.ModelSerializer):
user_name = serializers.CharField(source='user.fullname', read_only=True)
user_email = serializers.EmailField(source='user.email', read_only=True)
class Meta:
model = QuizParticipant
fields = [
'id',
'user_id',
'user_name',
'user_email',
'started_at',
'ended_at',
'total_timing',
'question_score',
'timing_score',
'total_score'
]
class AdminQuizAbsenteeSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'fullname', 'email']

12
apps/quiz/urls.py

@ -1,13 +1,21 @@
from django.urls import path
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views
router = DefaultRouter()
router.register(r'admin/quizzes', views.AdminQuizViewSet, basename='admin-quizzes')
router.register(r'admin/questions', views.AdminQuestionViewSet, basename='admin-questions')
urlpatterns = [
path('', include(router.urls)),
path('admin/courses/', views.AdminCourseListView.as_view(), name='admin-courses-list'),
path('admin/lessons/', views.AdminLessonListView.as_view(), name='admin-lessons-list'),
# path('prizes/', PrizeListAPIView.as_view()),
# path('ranked-list/', RankedListAPIView.as_view()),
# path('self-rank/', SelfRankAPIView.as_view()),
# path('my-quizzes/', UserQuizScores.as_view()),
path('submit-quiz/', views.QuizParticipantCreateAPIView.as_view()),
path('<int:quiz_id>/', views.QuizDetailAPIView.as_view()),
]

1
apps/quiz/views/__init__.py

@ -1,2 +1,3 @@
from .quiz import *
from .participant import *
from .admin import *

156
apps/quiz/views/admin.py

@ -0,0 +1,156 @@
from django.db.models import Q
from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from apps.quiz.models import Quiz, Question, QuizParticipant
from apps.course.models import Course, CourseLesson, Participant
from apps.account.models import User
from apps.quiz.serializers.admin import (
AdminCourseSerializer,
AdminCourseLessonSerializer,
AdminQuizListSerializer,
AdminQuizDetailSerializer,
AdminQuestionSerializer,
AdminQuizParticipantSerializer,
AdminQuizAbsenteeSerializer
)
class AdminQuizViewSet(ModelViewSet):
"""
Admin CRUD ViewSet for Quiz management.
Includes searching, filtering, and retrieving participants/absentees list.
"""
permission_classes = [IsAuthenticated, IsAdminUser]
authentication_classes = [TokenAuthentication]
def get_serializer_class(self):
if self.action == 'list':
return AdminQuizListSerializer
return AdminQuizDetailSerializer
def get_queryset(self):
queryset = Quiz.objects.all().select_related('course', 'lesson')
# Handle Search
search_query = self.request.query_params.get('search', None)
if search_query:
queryset = queryset.filter(
Q(title__icontains=search_query) |
Q(description__icontains=search_query)
)
# Handle Course Filter
course_id = self.request.query_params.get('course', None)
if course_id:
queryset = queryset.filter(course_id=course_id)
# Handle Lesson Filter
lesson_id = self.request.query_params.get('lesson', None)
if lesson_id:
queryset = queryset.filter(lesson_id=lesson_id)
# Handle Status Filter
status_param = self.request.query_params.get('status', None)
if status_param is not None:
if status_param.lower() == 'true':
queryset = queryset.filter(status=True)
elif status_param.lower() == 'false':
queryset = queryset.filter(status=False)
return queryset.order_by('-id')
@action(detail=True, methods=['get'])
def participants(self, request, pk=None):
"""
Returns two lists:
1. Participants: users who have participated in the quiz.
2. Absentees: users who are enrolled in the course but have not participated.
"""
quiz = self.get_object()
# 1. Fetch participants
participants_qs = QuizParticipant.objects.filter(quiz=quiz).select_related('user')
participants_serializer = AdminQuizParticipantSerializer(participants_qs, many=True)
# 2. Fetch absentees
absentees_data = []
if quiz.course:
# Enrolled course student IDs
enrolled_student_ids = Participant.objects.filter(
course=quiz.course,
is_active=True
).values_list('student_id', flat=True)
# Participated user IDs
participated_user_ids = participants_qs.values_list('user_id', flat=True)
# Absentee IDs
absentee_ids = set(enrolled_student_ids) - set(participated_user_ids)
# Fetch User details for absentees
absentees_qs = User.objects.filter(id__in=absentee_ids)
absentees_serializer = AdminQuizAbsenteeSerializer(absentees_qs, many=True)
absentees_data = absentees_serializer.data
return Response({
'participants': participants_serializer.data,
'absentees': absentees_data
})
class AdminQuestionViewSet(ModelViewSet):
"""
Admin CRUD ViewSet for Question management.
Usually filtered by quiz_id.
"""
serializer_class = AdminQuestionSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
authentication_classes = [TokenAuthentication]
pagination_class = None
def get_queryset(self):
queryset = Question.objects.all()
quiz_id = self.request.query_params.get('quiz_id', None)
if not quiz_id:
# Fallback parameter name
quiz_id = self.request.query_params.get('quiz', None)
if quiz_id:
queryset = queryset.filter(quiz_id=quiz_id)
return queryset.order_by('priority', 'id')
class AdminCourseListView(ListAPIView):
"""
Dropdown listing helper for all courses.
"""
queryset = Course.objects.all().order_by('-id')
serializer_class = AdminCourseSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
authentication_classes = [TokenAuthentication]
pagination_class = None # Return all courses for dropdown usage
class AdminLessonListView(ListAPIView):
"""
Dropdown listing helper for lessons. Filtered by course_id.
"""
serializer_class = AdminCourseLessonSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
authentication_classes = [TokenAuthentication]
pagination_class = None # Return all matching lessons for dropdown usage
def get_queryset(self):
course_id = self.request.query_params.get('course_id', None)
if course_id:
return CourseLesson.objects.filter(course_id=course_id).select_related('lesson').order_by('priority')
return CourseLesson.objects.all().select_related('lesson').order_by('-id')
Loading…
Cancel
Save