调用嵌套的Serializer的.update()方法

问题描述 投票:1回答:1

我的模型中有一个JSONField,它存储了一些配置数据。我想访问这个字段(读取和写入),能够对内部字段及其值进行部分更新。

出于举例的目的,让一个模型称为MyModel,其中JSONField称为config

class MyModel(models.Model):
    config = JSONField(default=dict())
    ...

我创建了一个单独的ViewSet来访问存储在config字段中的信息。假设user模型与ForeignKeyMyModel关系。这个ViewSet的简化版本是:

class ConfigurationFieldViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):

serializer_class = MyModelConfigurationSerializer

def get_object(self):
    return self.request.user.my_model

存储在config中的数据具有一定的结构,包含几个可能的内部对象:

{
    "C1": {"counter": 42, "active": false},
    "C2": {"counter": 13, "active": true}
}

要在所有嵌套级别访问并正确序列化MyModel实例,我已经为每个级别的字段创建了序列化器。要在config本身访问MyModel字段,我正在使用此序列化程序:

class MyModelConfigurationSerializer(serializers.ModelSerializer):
    configuration = ConfigurationFieldSerializer(required=True)

    class Meta:
        model = MyModel
        fields = ('configuration',)

要访问和序列化第一层configuration字段,有第二个序列化器:

class ConfigurationFieldSerializer(serializers.Serializer):
    C1 = BaseConfigurationSerializer(required=True)
    C2 = BaseConfigurationSerializer(required=True)

最后访问每个C1C2字段的内部结构有第三个序列化器:

class BaseConfigurationSerializer(serializers.Serializer):

    counter = serializers.IntegerField(
        required=False,
        help_text=_('Some integer field help text')
    )
    active = serializers.BooleanField(
        required=False,
        help_text=_('Some boolean field description')
    )

上面的代码完美地用于读取存储在config字段中的数据并正确地序列化它的内部对象。当我尝试在此字段上执行PUT时出现问题。

如果我在update级别覆盖MyModelConfigurationSerializer方法,那么序列化程序验证我提交的数据,但作为一个块,我只能一次保存它。如果我试图提交一些内部字段,我仍然正确地通过内部序列化器接收验证错误。

    def update(self, instance, validated_data):
        instance.configuration = validated_data.get(
            'configuration', instance.configuration
        )
        instance.save()
        return instance

我无法做的是调用内部序列化器的update方法(在这种情况下为ConfigurationFieldSerializerBaseConfigurationSerializer):如果我实现他们的update方法,他们根本就不会被调用。

根据DRF Documentation可写的嵌套表示是可能的,并且每当在顶级序列化器上调用update时,应调用相应的createupdate方法。

python django django-rest-framework django-serializer
1个回答
0
投票

我最近也遇到过这个问题,看起来你做这件事的方式是嵌套可写序列化器的“唯一方法”。

same DRF docs你可能已经看到:

由于嵌套创建和更新的行为可能不明确,并且可能需要相关模型之间的复杂依赖关系,因此REST框架3要求您始终显式编写这些方法。默认的ModelSerializer .create()和.update()方法不包括对可写嵌套表示的支持。

但是,可用的第三方软件包(如DRF Writable Nested)支持自动可写嵌套表示。

基本上它意味着当你有嵌套时,它甚至不会尝试调用任何嵌套的串行器存储方法。

这可能看起来有点痛苦,但回想起来,它可能更适合您的应用程序的设计。您的示例非常简单,但在其他情况下,保存事物的顺序可能很重要。如果每个嵌套序列化程序的update都是自动运行的,那么DRF必须知道何时保存每个东西。

例如,如果您的示例是关于create而不是update,那么这意味着您需要首先存储模型MyModel,然后再将配置存储在其上。但DRF无法知道这一点。

此外,它很容易就是配置实际上是另一个需要先保存的相关模型,然后才能从MyModel中保存它的关系。所以DRF在根序列化器上采取了告诉你自己做的路线。

根据我自己的经验,这也有助于您稍后调整性能(例如,在您的情况下,您可以避免两次保存MyModel)。

最后,如果您想使代码更加模块化,您仍然可以执行此操作(将经过验证的数据段发送给不同的处理程序,例如发送到新的update_configurations()函数),它不会使用嵌套的序列化程序自动完成。

© www.soinside.com 2019 - 2024. All rights reserved.