'How to POST multiple objects in one JSON request?

I am using django-rest-framework and recently I encountered a problem. I need to post such request and get 2 objects created:

{
    "lease": 28,
    "date": [
        {
            "from_date": "2021-06-01",
            "until_date": "2021-07-01"
        },
        {
            "from_date": "2022-03-22",
            "until_date": "2022-04-23"
        }
    ]
}

Model looks like this:

class DateUnavailable(models.Model):
    lease = models.ForeignKey(Lease, on_delete=models.CASCADE, blank=False, null=False)
    from_date = models.DateField(blank=True, null=True)
    until_date = models.DateField(blank=True, null=True)

How that can be accomplished? I tried Serializer(many=true) in views.py, but it does not work



Solution 1:[1]

I had the same issue you are having, then what I have done was create a model that had the fields as a ManyToManyField() to allow the creation of multiple nested fields:

Bear in mind that the default DRF forms will not allow multiple posts. You will need to pass them directly as json format.

models

class ProfileProperty(models.Model):
    gender = models.CharField(....)
    height = models.DecimalField(..)
    width = models.DecimalField(...)
    
    ....
 
class Profile(models.Model):
    name = models.CharField(User, on_delete=models.CASCADE)
    property = models.ManyToManyField(ProfileProperty) # <------------------------
 
    def __str__(self):
        return self.name

Serializers

imports ...
 
Class ProfilePropertySerializer(serializer.ModelSerializer):
 
    class Meta:
        model = ProfileProperty
        fields = "__all__"
 
 
Class ProfileSerializer(serializer.ModelSerializer):
 
    property = ProfilePropertySerializer(many=True)
 
    class Meta:
        model = Profile
        fields = "__all__"
 
    def create(self, validate_data):
        # get the value from the payload.
        properties = validated_data.pop('property')
 
        # Add (all) the value from payload to the Profile model.
        profile_instance = Profile.objects.create(**validated_data)
 
        # Loop the values that were passed inside of property fields from payload.
        for property in properties:
           # Add normally the fields of "this payload" to the Property model.
           property_instance = Property.objects.create(**property)
           
           # Here is where the magic begins:
           # Get the property_instance and passes all the payloads.id.
           # and add them to profile_instance as it should be.
           profile_instance.property.add(property_instance.id)
           
           # save the values.
           profile_instance.save()
 
           return profile_instance
 
    def update(self, instance, validate_data):
        # do awesome stuff here... ;)
 

Payload

[
 {
  "id":1,
  "name":"John Smith",
  "property":[
        {
         "gender":"Male",
         "height": 1.72,
         "width":null
         },
         {
         "gender":"Male",
         "height": 1.90,
         "width":null
         },
         {
         "gender":"Male",
         "height": 1.72,
         "width":null
         },
       ]
    }
]

Solution 2:[2]

Make your payload a JSON array. It should work with many=True

[
    {
        "lease": 28,
        "from_date": "2021-06-01",
        "until_date": "2021-07-01"
    },
    {
        "lease": 28,
        "from_date": "2022-03-22",
        "until_date": "2022-04-23"
    }
]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 MjZac