Search code examples
django-modelsdjango-rest-frameworkdjango-serializer

How to Implement One to Many in DRF


I am Designing a Model

class Timer(models.Model):
    total_time = models.FloatField(default=5)
    date_time = models.DateTimeField(auto_now_add=True)


class WatchTiming(models.Model):
    user = models.OneToOneField("authentication.User", on_delete=models.CASCADE, primary_key=True)
    current_timer = models.ForeignKey(Timer, on_delete=models.CASCADE, related_name="current_timer")
    previous_timers = models.ForeignKey(Timer, on_delete=models.CASCADE, related_name="previous_timers")

and serializer for this model is

from rest_framework import serializers

from .models import Timer, WatchTiming


class TimerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Timer
        exclude = ("id",)


class WatchTimingSerializer(serializers.ModelSerializer):
    current_timer = TimerSerializer(required=False)
    previous_timers = TimerSerializer(many=True, read_only=True)
    user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = WatchTiming
        fields = "__all__"

    def create(self, validated_data):
        watch_timing = WatchTiming.objects.create(user=self.context["request"].user, current_timer=Timer.objects.create())
        return watch_timing

WatchTiming is a table that is used to store user watch time

current_timer stores today's timer when the day expires current_timer values are added in the previous_timer and the current_timer value is replaced with the default

Now My issue is how can I create one to many relationships, I already have written relationships but its not working

I have been stuck on this for 4 consecutive days.


Solution

  • You can use a subserializer, just like you did with your TimerSerializers:

    from rest_framework import serializers
    
    from .models import Timer, WatchTiming
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User  # authentication.User
            fields = (
                'id',
                'username',
            )
    
    
    class WatchTimingSerializer(serializers.ModelSerializer):
        current_timer = TimerSerializer(required=False)
        previous_timers = TimerSerializer(read_only=True)
        user = serializers.UserSerializer(read_only=True)
    
        class Meta:
            model = WatchTiming
            fields = '__all__'
    
        def create(self, validated_data):
            return WatchTiming.objects.create(
                user=self.context['request'].user,
                current_timer=Timer.objects.create(),
            )

    Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


    Note: The related_name=… parameter [Django-doc] is the name of the relation in reverse, so from the Timer model to the WatchTiming model in this case. Therefore it (often) makes not much sense to name it the same as the forward relation. You thus might want to consider renaming the current_timer relation to watch_timings.