简体   繁体   中英

Django REST Framework nested serializer won't update

As per the Django REST Framework version 3 documentation , in order to create a writable nested serializer, you need to write your own create() and update() methods. I've got reading and writing working, but update does not work.

For example, if I send the following data into my serializer 3 times, I end up with 3 new Widgets created. I expected passing in a pre-existing id would trigger an update and call update() , but create() gets called instead. Seems like id is ignored which sorta makes sense since it's auto generated, so how do I achieve this?

I have a feeling I'm missing something obvious, perhaps some extra handling in my view?

views.py (really rough at the moment, please excuse)

from rest_framework.decorators import api_view
from rest_framework.response import Response

from widget.models import Widget
from widget.serializers import WidgetSerializer

@api_view()
def create(request):

    data = {
        "id": 4,
        "widget_alpha": {
            "bits": [
                {
                    "id": 3,
                    "name": "bit 1",
                    "widget": 4
                }
            ],
            "bobs": [
                {
                    "id": 3,
                    "name": "bob 1",
                    "widget": 4
                }
            ],
            "name": "my wid",
            "widget": 4
        },
        "language": "en",
        "code": "123"
    }

    serializer = WidgetSerializer(data=data)
    if serializer.is_valid():
        serializer.save()
    else:
        print serializer.errors

    return Response({"message": "yay"})

Widget is a parent model, WidgetAlpha is a child and is comprised of several Bits and Bobs. Related models.py and serializers.py code below.

models.py

from django.db import models

class Widget(models.Model):
    LANGUAGE = (
        ('fr', 'French'),
        ('en', 'English'),
    )

    language = models.CharField(max_length=2, choices=LANGUAGE)
    code = models.CharField(max_length=6)

class WidgetAlpha(models.Model):
    widget = models.OneToOneField(Widget, primary_key=True, related_name='widget_alpha')
    name = models.CharField(max_length=6)

class Bit(models.Model):

    widget = models.ForeignKey(WidgetAlpha, related_name='bits')
    name = models.CharField(max_length=6)

class Bob(models.Model):

    widget = models.ForeignKey(WidgetAlpha, related_name='bobs')
    name = models.CharField(max_length=6)

serializers.py

from rest_framework import serializers

from widget.models import Widget, WidgetAlpha, Bit, Bob

class BitsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bit

class BobsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bob

class WidgetAlphaSerializer(serializers.ModelSerializer):

    bits = BitsSerializer(many=True)
    bobs = BobsSerializer(many=True)

    class Meta:
        model = WidgetAlpha

class WidgetSerializer(serializers.ModelSerializer):
    widget_alpha = WidgetAlphaSerializer()

    class Meta:
        model = Widget

    def create(self, validated_data):
        widget_alpha_data = validated_data.pop('widget_alpha')      
        bits_data = widget_alpha_data.pop('bits')
        bobs_data = widget_alpha_data.pop('bobs')

        widget = Widget.objects.create(**validated_data)
        alpha_widget = WidgetAlpha.objects.create(widget=widget, **widget_alpha_data)

        for bit_data in bits_data:
            Bit.objects.create(widget=alpha_widget, **bit_data)

        for bob_data in bobs_data:
            Bob.objects.create(widget=alpha_widget, **bob_data)

        return widget

    def update(self, instance, validated_data):
        # never get here :(
        return instance

In order .update() method of WidgetSerializer to be called you need to instantiate serializer differently.

Try using something like this:

widget = Widget.get(pk=something)

serializer = WidgetSerializer(widget, data=data, partial=True) #you need partial if you want to update only some fields
if serializer.is_valid():
    serializer.save()
else:
    print serializer.errors

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM