Search code examples
pythondjangodjango-rest-frameworkdjango-serializer

DRF : Getting nestted serializer fields for custom checks


My Model Classes

class Master(models.Model):
    date_signed= models.DateField()
    info1 = models.CharField(max_length=255)
    info2 = models.CharField(max_length=255)

class Detail(models.Model):
    date_start = models.DateField()
    date_end = models.DateField()
    info3 = models.CharField(max_length=255)
    info4 = models.CharField(max_length=255)
    master = models.OneToOneField(Master,on_delete=models.CASCADE,related_name='detail')

Here is my master and detail serializers.

class MasterSerializer(serializers.ModelSerializer):
  
     class Meta:
         model = Master
         fields = ['id','date_signed','info1','info2']

class DetailSerializer(serializers.ModelSerializer):
     master = MasterSerializer(read_only=True)

     class Meta:
         model = Detail
         fields = ['id','master','date_start','date_end','info3','info4'...]

     def validate(self, attrs):
         # 1. check if date sign is always grater than date start
         # 2. check date start is greater than date end

What i am trying to do is to check if the date_signed in master serializer is always a date before the date_start one. For that i need the date_signed in the detail serializer. So how can i get it. May be is a simpler question, but i am finding it difficult as i just started learning drf. I searched a lot, but couldnt get the solution i needed.

Hope to get some help to point me in the right direction.

Thanks in advance


Solution

  • If you want to use context for master_id.

    class MasterSerializer(serializers.ModelSerializer):
      
         class Meta:
             model = Master
             fields = ['id','date_signed','info1','info2']
    
    class DetailSerializer(serializers.ModelSerializer):
         master = MasterSerializer(read_only=True)
    
         class Meta:
             model = Detail
             fields = ['id','master','date_start','date_end','info3','info4'...]
    
         def validate(self, attrs):
             # 1. check if date sign is always grater than date start
             if Master.objects.get(id=self.context.get("master_id")).date_signed > attrs.get("date_start"):
                 raise ValidationError(detail="Error Message!")
             # 2. check date start is greater than date end
             if attrs.get("date_start") > attrs.get("date_end"):
                 raise ValidationError(detail="Error Message!")
             return attrs
    

    Instead of using context for master_id in this we are using payload. If we want to change to representation of our serializer then we need to override this to_representation function.

    class MasterSerializer(serializers.ModelSerializer):
      
         class Meta:
             model = Master
             fields = ['id','date_signed','info1','info2']
    
    class DetailSerializer(serializers.ModelSerializer):
         master = serializers.PrimaryKeyRelatedField(queryset=Master.objects.all())
    
         class Meta:
             model = Detail
             fields = ['id','master','date_start','date_end','info3','info4'...]
    
         def to_representation(self, obj):
             data = super().to_representation(obj)
             data.update({"master": MasterSerializer(obj.master).data})
             return data
    
         def validate(self, attrs):
             # 1. check if date sign is always grater than date start
             if attrs.get("master").date_signed > attrs.get("date_start"):
                 raise ValidationError(detail="Error Message!")
             # 2. check date start is greater than date end
             if attrs.get("date_start") > attrs.get("date_end"):
                 raise ValidationError(detail="Error Message!")
             return attrs