Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 调用嵌套序列化程序';s.update()方法_Python_Django_Django Rest Framework_Django Serializer - Fatal编程技术网

Python 调用嵌套序列化程序';s.update()方法

Python 调用嵌套序列化程序';s.update()方法,python,django,django-rest-framework,django-serializer,Python,Django,Django Rest Framework,Django Serializer,我的模型中有一个JSONField,用于存储一些配置数据。我想访问这个字段(读和写),能够对内部字段及其值进行部分更新 例如,让一个模型被称为MyModel,而JSONField被称为config: class MyModel(models.Model): config = JSONField(default=dict()) ... 我创建了一个单独的ViewSet来访问config字段中存储的信息。假设user模型与MyModel有ForeignKey关系。此视图集的简化版本

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

例如,让一个模型被称为
MyModel
,而
JSONField
被称为
config

class MyModel(models.Model):
    config = JSONField(default=dict())
    ...
我创建了一个单独的
ViewSet
来访问
config
字段中存储的信息。假设
user
模型与
MyModel
ForeignKey
关系。此
视图集的简化版本为:

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
实例,我为每个字段级别创建了序列化程序。要访问
MyModel
本身中的
config
字段,我使用此序列化程序:

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

    class Meta:
        model = MyModel
        fields = ('configuration',)
class ConfigurationFieldSerializer(serializers.Serializer):
    C1 = BaseConfigurationSerializer(required=True)
    C2 = BaseConfigurationSerializer(required=True)
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')
    )
要访问和序列化
配置的第一层
字段,有第二个序列化程序:

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

    class Meta:
        model = MyModel
        fields = ('configuration',)
class ConfigurationFieldSerializer(serializers.Serializer):
    C1 = BaseConfigurationSerializer(required=True)
    C2 = BaseConfigurationSerializer(required=True)
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')
    )
最后要访问每个
C1
C2
字段的内部结构,有第三个序列化程序:

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

    class Meta:
        model = MyModel
        fields = ('configuration',)
class ConfigurationFieldSerializer(serializers.Serializer):
    C1 = BaseConfigurationSerializer(required=True)
    C2 = BaseConfigurationSerializer(required=True)
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
时,会出现此问题

如果我在
MyModelConfigurationSerializer
级别重写
update
方法,那么序列化程序将验证我提交的数据,但将其作为块,并且我只能一次保存所有数据。如果我试图提交一些内部字段,我仍然正确地收到内部序列化程序的验证错误

    def update(self, instance, validated_data):
        instance.configuration = validated_data.get(
            'configuration', instance.configuration
        )
        instance.save()
        return instance
但是我不能做的是调用内部序列化程序的
update
方法(
ConfigurationFieldSerializer
BaseConfigurationSerializer
),如果我实现了它们的
update
方法,它们就不会被调用


根据可写性,嵌套表示是可能的,当在顶级序列化程序上调用
update
时,应该调用相应的
update
create
方法。

我最近也遇到了这个问题,看起来您这样做是“唯一的方法”当涉及到嵌套的可写序列化程序时

    def update(self, instance, validated_data):
        instance.configuration = validated_data.get(
            'configuration', instance.configuration
        )
        instance.save()
        return instance
从中您可能已经看到:

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

但是,也有第三方软件包,例如支持自动可写嵌套表示的DRF Writable Nested

基本上,这意味着当您进行嵌套时,它甚至不会尝试调用任何嵌套的序列化程序存储方法

这似乎有点痛苦,但回想起来,这对应用程序的设计可能更好。您的示例非常简单,但在其他情况下,保存内容的顺序可能很重要。如果自动运行每个嵌套序列化程序的
update
,则DRF必须知道何时保存每个内容

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

同样很容易的是,配置实际上是另一个相关模型,需要先保存它,然后才能从
MyModel
保存与它的关系。因此,DRF采取的路线只是告诉您自己在根序列化程序中完成它

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


最后,如果您想使代码更加模块化,您仍然可以这样做(将已验证数据的段发送到不同的处理程序,例如发送到新的
update\u configurations()
函数),它只是不会使用嵌套序列化器自动完成。

我最近也遇到了这个问题,对于嵌套的可写序列化程序,您这样做似乎是“唯一的方法”

    def update(self, instance, validated_data):
        instance.configuration = validated_data.get(
            'configuration', instance.configuration
        )
        instance.save()
        return instance
从中您可能已经看到:

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

但是,也有第三方软件包,例如支持自动可写嵌套表示的DRF Writable Nested

基本上,这意味着当您进行嵌套时,它甚至不会尝试调用任何嵌套的序列化程序存储方法

这似乎有点痛苦,但回想起来,这对应用程序的设计可能更好。您的示例非常简单,但在其他情况下,保存内容的顺序可能很重要。如果自动运行每个嵌套序列化程序的
update
,则DRF必须知道何时保存每个内容

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

同样很容易的是,配置实际上是另一个相关模型,需要先保存,然后才能从保存与它的关系