Sheric
Sheric

Reputation: 416

Writable nested serializer on django rest framework validation error on the nested foreign key. Field is required

I am trying to make a writable nested serializer in Django Rest Framework. But I get validation error: slug is required. but it is the foreign key and it is not known before insert of the parent object takes place.

Here is my models and serializers:

Models:

class Letter(BaseModel):
    char = models.CharField(
        max_length=1,
    )
    slug = models.ForeignKey(
        to="core.LetterSlug",
        related_name="letters",
        on_delete=models.CASCADE,
    )


class LetterSlug(BaseModel):
    char = models.CharField(
        max_length=1,
    )

Serializers:

class LetterSerializer(serializers.ModelSerializer):
    class Meta:
        model = Letter
        fields = '__all__'


class LetterSlugSerializer(serializers.ModelSerializer):
    letters = LetterSerializer(many=True,instance=Letter.objects.all())

    class Meta:
        model = LetterSlug
        fields = ('char', 'letters')

    def create(self, validated_data):
        letter_data = validated_data.pop('letters')
        slug = LetterSlug.objects.create(**validated_data)
        Letter.objects.create(slug=slug, **letter_data)

        return slug

I expect it to add several Letter objects all of which share the same foreign key to the newly created LetterSlug object.

I tried commenting out contents of my create method, and made sure that it's during validations before calling create method.

Upvotes: 1

Views: 1216

Answers (1)

Ehsan Nouri
Ehsan Nouri

Reputation: 2040

just make slug readonly in LetterSerializer:

class LetterSerializer(serializers.ModelSerializer):
    class Meta:
        model = Letter
        fields = '__all__'
        read_only_fields = ("slug", )

also edit your other serializer as below:

class LetterSlugSerializer(serializers.ModelSerializer):
    letters = LetterSerializer(many=True)

    class Meta:
        model = LetterSlug
        fields = ('char', 'letters')

    def create(self, validated_data):
        letters_data = validated_data.pop('letters')
        slug = super().create(**validated_data)
        Letter.objects.bulk_create([ Letter(slug=slug, **letter) for letter in letters_data ])
        return slug

Upvotes: 1

Related Questions