【问题标题】:Django REST Framework nested serializer won't updateDjango REST Framework 嵌套序列化程序不会更新
【发布时间】:2016-01-13 16:19:56
【问题描述】:

根据 Django REST Framework 版本 3 documentation,为了创建可写的嵌套序列化程序,您需要编写自己的 create() 和 update() 方法。我的阅读和写作工作正常,但更新不起作用。

例如,如果我将以下数据发送到我的序列化程序 3 次,我最终会创建 3 个新的小部件。我预计传入一个预先存在的id 会触发更新并调用update(),但会调用create()。似乎id 被忽略了,因为它是自动生成的,所以这是有道理的,那么我该如何实现呢?

我感觉我遗漏了一些明显的东西,也许是我认为的一些额外处理?

views.py(目前真的很粗糙,请见谅)

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 是一个父模型,WidgetAlpha 是一个子模型,由几个 Bits 和 Bobs 组成。相关models.py 和serializers.py 代码如下。

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)

序列化器.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

【问题讨论】:

  • 您也可以添加您的视图吗?
  • views.py 已添加
  • 你不会在任何地方打电话给update。如果你想调用更新,你需要创建类似这样的序列化器对象:serializer = WidgetSerializer(object, data=data)
  • 是的,看起来就是这个问题,需要传递一个实例。来自文档:“调用 .save() 将创建一个新实例或更新现有实例,具体取决于在实例化序列化程序类时是否传递了现有实例:”
  • 那么,它奏效了吗?如果是这样,您可以将其发布为答案并接受吗?记得引用@DevilPinky 评论:)

标签: python django serialization django-rest-framework


【解决方案1】:

为了调用WidgetSerializer 的.update() 方法,您需要以不同的方式实例化序列化程序。

尝试使用类似的东西:

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

【讨论】:

  • 你能简单解释一下吗,因为我和你做的一样,但即使我无法调用 ModelSerializer 的 update()
  • @NikhilBhardwaj 你检查帖子上的 cmets 了吗?我在那里留下了评论,可能会解决您的问题。如果没有 - 请添加更多关于您正在做什么的上下文。
  • 我在更新唯一字段模型时遇到错误,例如,我有一个带有用户 a/c 和配置文件的嵌套序列化程序,一切正常,但是当我添加唯一的用户名字段时,如果我不更新该字段,然后我得到用户名应该是唯一的错误,我不想更新用户名....
  • 所以你的情况不同。不看代码很难说,但我认为你必须编写自己的更新函数,在其中添加所有需要的逻辑。
猜你喜欢
  • 2016-02-09
  • 2017-01-28
  • 1970-01-01
  • 2018-10-26
  • 2014-12-21
  • 1970-01-01
  • 2017-12-03
  • 2019-08-10
  • 2023-03-26
相关资源
最近更新 更多