dan_boy
dan_boy

Reputation: 2009

How to send a post request via postman to nested writable serializer in django-rest-framework?

I'm really struggling with sending my data with postman in correct form to my Django backend. I followed the approach in the Django documentation for a writeable nested Seralizer and adapted it to my case. If I pass the data to my serializer via the shell, everything works and I can create the two object instances Story and File. But if I try to do the same with post man, it is not successful and receive the following error Message: Got AttributeError when attempting to get a value for field 'file' on serializer 'StoryCreateUpdateSerializer'. The serializer field might be named incorrectly and not match any attribute or key on the 'Story' instance. Original exception text was: 'Story' object has no attribute 'file'.

Successfull Request via Shell:

>>> data = {
    'title': 'HALLLO',
    'file': [
        {'content': 'Public Service Announcement'},
        {'content': 'Public Service Announcement'},
        {'content': 'Public Service Announcement'},
    ],
}
>>> serializer = StoryCreateUpdateSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()

Not Successfull Request via Postman. Header: Content-Type: application/json. Body: Raw

{
    "title": "Test",
    "file": [
        {
            "content": "Hallo"
        }
    ]
}

My models and Serializers

#MODELS
class Story (models.Model):
    title = models.CharField(max_length=100,blank=True)
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)

class File(models.Model):
    story = models.ForeignKey(Story,on_delete=models.CASCADE, null=True)
    content = models.TextField(blank=False, null=True)
#SERIALIZER
class TestFileSerializer (serializers.ModelSerializer):

    class Meta:
        model = File
        fields =  ('content',)

class StoryCreateUpdateSerializer (serializers.ModelSerializer):
    file = TestFileSerializer(many=True)

    class Meta:
        model = Story
        fields =  ('title','file')

    def create(self, validated_data):
        current_user = self.context["request"].user
        title = validated_data.pop('title')
        file = validated_data.pop('file')
        story_instance = Story.objects.create(author=current_user, title=title)

        for file_data in file:
            File.objects.create(**file_data, story=story_instance)
        return story_instance
#VIEW
class StoryCreateUpdateViewSet(viewsets.ModelViewSet):
    serializer_class = StoryCreateUpdateSerializer

    queryset = Story.objects.all()

I'am happy for any clarification. As i running out of ideas.

Upvotes: 0

Views: 869

Answers (1)

Sajjad Sanikhani
Sajjad Sanikhani

Reputation: 396

In ForeignKey field of File model, default related_name and related_query_name attributes are 'file_set' not 'file'

So you should do one of these changes on your code:


Method 1:
In File model add related_name and related_query_name attributes to ForeignKey field with values 'file':

story = models.ForeignKey(
    Story,
    on_delete=models.CASCADE,
    null=True,
    related_name = 'file',
    related_query_name = 'file'
)

Method 2:
In StoryCreateUpdateSerializer change 'file' field to 'file_set':

class StoryCreateUpdateSerializer (serializers.ModelSerializer):
    file_set = TestFileSerializer(many=True)

    class Meta:
        model = Story
        fields =  ('title','file_set')

    def create(self, validated_data):
        current_user = self.context["request"].user
        title = validated_data.pop('title')
        file = validated_data.pop('file')
        story_instance = Story.objects.create(author=current_user, title=title)

        for file_data in file:
            File.objects.create(**file_data, story=story_instance)
        return story_instance

In this method, also you've to change your request body properties and substitute 'file' with 'file_set'

Upvotes: 2

Related Questions