Oz Bar-Shalom
Oz Bar-Shalom

Reputation: 1855

Django rest - Serialize nested objects

I am using Django 1.10.5 and djangorestframework 3.5.3.

I have 2 models that are related with one to many relation:

class Minisymposium(models.Model):
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('approved', 'Approved'),
        ('denied', 'Denied'))

    id = models.AutoField(primary_key=True)
    number = models.IntegerField(default=0, null=False)
    title = models.CharField(max_length=100, null=False)
    description = models.TextField(max_length=9000, null=False)
    status = models.CharField(max_length=100, choices=STATUS_CHOICES, null=False, default='pending')
    user = models.ForeignKey(User, null=False, related_name='user')
    corresponding_organizer = models.ForeignKey(User, null=False, related_name='corresponding_organizer')
    anticipated_abstracts = models.IntegerField(null=False)
    anticipated_attendees = models.IntegerField(null=False)
    date = models.DateTimeField(auto_now_add=True)

def __str__(self):
    return '{0}-{1}'.format(self.number, self.title)

class UnregisteredOrganizer(models.Model):
    id = models.AutoField(primary_key=True)
    first_name = models.CharField(max_length=1000, blank=False)
    last_name = models.CharField(max_length=1000, blank=False)
    email = models.EmailField(max_length=254, blank=True)
    affiliation = models.CharField(max_length=254, help_text='(institution only)', blank=True)
    phone_number = PhoneNumberField(blank=True)
    minisymposium = models.ForeignKey(Minisymposium, related_name='other_organizers')

Each model have a serializer. But the problem is with Minisymposium`s serializer. Because I want to send an UnregisteredOrganizer`s ID on creating one, and get the whole object as serialized on getting a Minisymposium. And as I see in ModelSerializer it is not possible:

class MinisymposiumSerializer(serializers.ModelSerializer):
    other_organizers = UnregisteredOrganizerSerializer(many=True)

    class Meta:
        model = Minisymposium
        fields = ('url', 'id', 'number', 'title', 'description', 'status', 'user', 'corresponding_organizer',
                  'anticipated_abstracts', 'anticipated_attendees', 'other_organizers', 'date')

    def create(self, validated_data):
        other_organizers = []

        if 'other_organizers' in validated_data:
            other_organizers = validated_data.pop('other_organizers')

        minisymposium = Minisymposium.objects.create(**validated_data)
        minisymposium.save()

        for organizer in other_organizers:
            UnregisteredOrganizer.objects.create(minisymposium=minisymposium, **organizer).save()

        return minisymposium

How can I do that? Thank you !

Upvotes: 0

Views: 751

Answers (1)

Linovia
Linovia

Reputation: 20996

Because I want to send an UnregisteredOrganizer`s ID on creating one, and get the whole object as serialized on getting a Minisymposium.

Why have such an inconsistent API ?

The recommended option here is to set the fields on Minisymposium as read_only except for the id which should be read_only=False.

Therefore, you can get the full object when getting the data and just expect the id when post/put/patching the data. Posted JSON would look like:

{
    ...
    "url": "whatever",
    "title": "Some nice title",
    "other_organizers": [{"id": 5}, {"id": 5123}]
}

Creation code would be like:

def create(self, validated_data):
    other_organizers = validated_data.pop('other_organizers', [])

    minisymposium = Minisymposium.objects.create(**validated_data)
    minisymposium.save()

    organizers = []
    for organizer_id in other_organizers:
      organizers .append(UnregisteredOrganizer.objects.get(id=organizer_id)
    minisymposium. other_organizers = organizers

    return minisymposium

Upvotes: 2

Related Questions