Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework: override create() in ModelSerializer passing an extra parameter

I am looking for a way to properly ovverride the default .create() method of a ModelSerializer serializer in Django Rest Framework for dealing with an extra parameter.

In my original Django model I have just overridden the default.save() method for managing an extra param. Now .save() can be called also in this way: .save(extra = 'foo').

I have to create a ModelSerializer mapping on that original Django model:

from OriginalModels.models import OriginalModel
from rest_framework import serializers

class OriginalModelSerializer(serializers.ModelSerializer):

    # model fields
    class Meta:
        model = OriginalModel

But in this way I can't pass the extra param to the model .save() method.

How can I properly override the .create() method of my OriginalModelSerializer class to take (eventually) this extra param into account?

like image 861
floatingpurr Avatar asked Jun 04 '15 17:06

floatingpurr


People also ask

How do you pass extra context data to Serializers in Django REST framework?

In function-based views, we can pass extra context to serializer with “context” parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with “self. context”. From example, to get “exclude_email_list” we just used code 'exclude_email_list = self.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.


2 Answers

Hmm. this might not be the perfect answer given I don't know how you want to pass this "extra" in (ie. is it an extra field in a form normally, etc)

What you'd probably want to do is just represent foo as a field on the serializer. Then it will be present in validated_data in create, then you can make create do something like the following

def create(self, validated_data):
    obj = OriginalModel.objects.create(**validated_data)
    obj.save(foo=validated_data['foo'])
    return obj

You'd probably want to look at the default implementation of create for some of the other things it does though (like remove many-to-many relationships, etc.).

like image 60
Alex T Avatar answered Sep 17 '22 15:09

Alex T


You can now do this in the view set (threw in user as a bonus ;) ):

class OriginalModelViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows OriginalModel classes to be viewed or edited.
    """
    serializer_class = OriginalModelSerializer
    queryset =  OriginalModel.objects.all()
    def perform_create(self, serializer):
        user = None
        if self.request and hasattr(self.request, "user"):
            user = self.request.user
        serializer.save(user=user, foo='foo')

That way the Serializer can stay generic, i.e.:

class OriginalModelSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = OriginalModel
        fields = '__all__'
like image 25
davmor Avatar answered Sep 18 '22 15:09

davmor