Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-rest-framework, nested objects in Serializers

I would like to have a nested object inside a serializer instead of just the foreignkey (or url). As this documentation says, I just had to specify the serializer class of the nested object in the parent serializer:

# Models

class NestedSample(models.Model):
    something = models.CharField(max_length=255)

class Sample(models.Model):
    thing = models.BooleanField()
    nested = models.ForeignKey(NestedSample)

# Serializers

class NestedSampleSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = api_models.NestedSample

class SampleSerializer(serializers.HyperlinkedModelSerializer):
    nested = NestedSampleSerializer() # HERE!

    class Meta:
        model = api_models.Sample

# Views

class NestedSampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.NestedSample.objects.all()
    serializer_class = api_serializers.NestedSampleSerializer

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

This works very well when I get the objects, but it is not possible to create (=POST) Sample objects anymore, I get the error:

{u'non_field_errors': [u'Invalid data']}

I tried to overwrite the create method in the viewset to get the object using the pk:

class SampleViewSet(viewsets.ModelViewSet):
    queryset = api_models.Sample.objects.all()
    serializer_class = api_serializers.SampleSerializer

    def create(self, request):
        request.DATA['nested'] = get_object_or_404(api_models.NestedSample, pk=request.DATA['nested'])
        return super(SampleViewSet, self).create(request)

But it doesn't work as well.

Any idea?

I also found this question I can relate with which of course solves the problem but do not let me expose the full nested object, so back to the beginning.

Thanks,

like image 230
db0 Avatar asked May 19 '14 17:05

db0


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.

Do we need Serializers in Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

What is the use of nested serializer?

DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.

How do I pass Queryset to serializer?

To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.


1 Answers

I can think of two solutions to this problem. I prefer the first one.

First solution:

Use a django model form to create objects. Override the create and update methods. A sample create method:

def create(self, request):
    form = SampleForm(data=request.POST)
    if form.is_valid():
        instance = form.save(commit=False)
        instance.save()
        return Response(dict(id=instance.pk), status=status.HTTP_201_CREATED)
    return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)

this way you can create Sample objects with any kind of validation you like.

Second solution:

Override get_serializer_class method and return serializer class based on request method. Define two serializers one for post and put and one for list and retrieve.

like image 99
zaphod100.10 Avatar answered Sep 26 '22 19:09

zaphod100.10