0

I am making a back-end system using DRF in Django. This is my first project in Django and DRF. I am using Django purely as a REST back-end

I am making a quiz/mcq application

This is from my questions app, models.py

from django.db import models
from classifications.models import SubSubCategory

class Question(models.Model):
    ANSWER_TYPES = [
        ('single', 'Single Correct'),
        ('multiple', 'Multiple Correct'),
    ]

    text = models.TextField()
    answer_type = models.CharField(max_length=10, choices=ANSWER_TYPES, default='single')
    difficulty = models.CharField(
        max_length=10,
        choices=[('easy', 'Easy'), ('medium', 'Medium'), ('hard', 'Hard')],
        default='medium'
    )
    explanation = models.TextField(blank=True, null=True)
    subsubcategories = models.ManyToManyField(SubSubCategory, related_name='questions', blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    def __str__(self):
        return 'question'

    class Meta:
        ordering = ['-created_at']

    def correct_options(self):
        return self.options.filter(is_correct=True)

    def incorrect_options(self):
        return self.options.filter(is_correct=False)


class Option(models.Model):
    question = models.ForeignKey(Question, related_name='options', on_delete=models.CASCADE)
    label = models.CharField(max_length=5)
    text = models.TextField()
    is_correct = models.BooleanField(default=False)

    def __str__(self):
        return "options"


I am using Model viewset with router, but here when I try to create question, I have to request in two different endpoints: one for creating question and another for creating options for questions

views.py
from rest_framework import viewsets
from .models import Question, Option
from .serializers import QuestionSerializer, OptionSerializer
from core.permissions import IsAdminOrReadOnlyForAuthenticated
from django.db.models import Q

class OptionViewSet(viewsets.ModelViewSet):
    queryset = Option.objects.all()
    serializer_class = OptionSerializer

class QuestionViewSet(viewsets.ModelViewSet):
    queryset = Question.objects.all()
    serializer_class = QuestionSerializer


class SelectViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = QuestionSerializer
    queryset = Question.objects.none()

    def get_queryset(self):
        queryset = Question.objects.all().prefetch_related('subsubcategories')

        category_ids = self.request.query_params.getlist('category_id')
        subcategory_ids = self.request.query_params.getlist('subcategory_id')
        subsubcategory_ids = self.request.query_params.getlist('subsubcategory_id')

        category_ids = [int(x) for x in category_ids if x.isdigit()]
        subcategory_ids = [int(x) for x in subcategory_ids if x.isdigit()]
        subsubcategory_ids = [int(x) for x in subsubcategory_ids if x.isdigit()]

        q_filter = Q()

        if category_ids:
            q_filter |= Q(subsubcategories__subcategory__category__id__in=category_ids)
        if subcategory_ids:
            q_filter |= Q(subsubcategories__subcategory__id__in=subcategory_ids)
        if subsubcategory_ids:
            q_filter |= Q(subsubcategories__id__in=subsubcategory_ids)

        if q_filter:
            queryset = queryset.filter(q_filter)

        return queryset.distinct()


What should I do? Change the DB design so that all CRUD can be handled via model view set because currently to do operations of options I am having to request in different endpoint

This is my serializer currently

from rest_framework import serializers
from .models import Question, Option

class OptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Option
        fields = ('label','text','id')

class QuestionSerializer(serializers.ModelSerializer):
    options = OptionSerializer(many=True)
    class Meta:
        model = Question
        fields = ('id', 'text', 'answer_type', 'difficulty', 'explanation', 'subsubcategories', 'options')

Or do I have to write custom implementation for CRUD for options inside question

1 Answer 1

0

Override the create method of the QuestionSerializer to parse and create options.

from django.db import transaction


class QuestionSerializer(serializers.ModelSerializer):
    options = OptionSerializer(many=True) # This is correct

    class Meta:
        model = Question
        fields = ('id', 'text', 'answer_type', 'difficulty', 'explanation', 'subsubcategories', 'options')

    def create(self, validated_data):
        with transaction.atomic():
            options_data = validated_data.pop('options')
            
            question = Question.objects.create(**validated_data)
            
            for option_data in options_data:
                Option.objects.create(question=question, **option_data)
                
            return question

This will create the question and its options in a single API call. Override the update method also as needed.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.