Jatin Goyal
Jatin Goyal

Reputation: 497

Create multiple model instances of interlinked models through one post request in DRF

I want to create two entries from one post request. One in the 'Dates' model and one in 'Other' model. Code corresponding to both models is shown below.

class Dates(models.Model):
  booking_id = models.AutoField(primary_key=True)
  timestamp = models.DateTimeField(auto_now_add=True)
  feedback = models.CharField(max_length=8, default='no')
  myself = models.BooleanField(default=True)

  class Meta:
    app_label = 'bookings'

Other is:

class Other(models.Model):
  booking_id = models.OneToOneField(
                'bookings.Dates',
                null=False,
                default=1,
                primary_key=True,
                on_delete=models.CASCADE
            )
  name = models.CharField(max_length=64)
  phone_number = models.CharField(max_length=14)
  email_id = models.EmailField(max_length=128)

  class Meta:
    app_label = 'bookings'

I have validated the data from Dates Serializer and created the object in 'Dates' table. Now, I want to use the generated 'booking_id' as the same 'booking_id' for 'Other' table. How can I validate serializer and create an object in the 'Other' table while maintaining the consistency? Here with consistency, I mean: Either create objects in both the tables if no error occurs or don't create an object if any error occurs.

Upvotes: 0

Views: 536

Answers (1)

Ozgur Akcali
Ozgur Akcali

Reputation: 5482

You can make use of writable nested serializers to achieve this. You need to define a serializer class for Other model, then your Dates serializer can look like this:

class DatesSerializer(serializers.ModelSerializer):
    other = OtherSerializer()

    class Meta:
        model = Dates
        fields = ('timestamp', 'feedback', 'myself', 'other')

    def validate_other(self, value):
        # Run validations for Other model here, either manually or through OtherSerializer's is_valid method. You won't have booking_id in value here though, take that into account when modelling your validation process

    def validate_feedback(self, value):
        # Run validations specific to feedback field here, if necessary. You can do this for all serializer fields

    def validate(self, data):
        # Run non-field specific validations for Dates here

    def create(self, validated_data):
        # At this point, validation for both models are run and passed

        # Pop other model data from validated_data first
        other_data = validated_data.pop('other')

        # Create Dates instance 
        dates = Dates.objects.create(**validated_data)

        # Create Other instance now
        Other.objects.create(booking_id=dates, **other_data)

        return dates

You can use the defaul CreateModelMixin of DRF here, all nested object logic is handled in the serializer.

Upvotes: 2

Related Questions