【问题标题】:Writable nested serializer in django-rest-framework?django-rest-framework 中的可写嵌套序列化程序?
【发布时间】:2016-01-14 08:41:47
【问题描述】:

关于 Django ModelSerializer,我的设计如下。 有模型A和模型B。模型B有模型A的外键字段。由于某些原因,我不能直接使用主键序列化模型B。按照我的想法,我需要的是序列化另外两个字段(在模型 A 中是独一无二的)。

我看到 SlugRelatedField 必须用于一个 slug 字段。 我搜索了有一个 NaturalKeyField 可以支持 NaturalKeyField。但看起来它被 django-rest-framework 取代了。但是我检查了django-rest-framework,根本没有这个字段。 有人可以帮忙吗??我该怎么办?

代码如下。 A型

class AssetModel(models.Model):
    org = models.ForeignKey(Org, related_name='models')
    name = models.CharField(max_length=128)
    model_type = models.SmallIntegerField(default = 3,choices = MODEL_TYPE )
    directory = models.CharField(max_length = 128)
    ...
    class Meta:
        unique_together = ('org', 'name',)

模型 B

class Dataitem(models.Model):
    mod = models.ForeignKey(AssetModel, related_name='dataitems')
    name = models.CharField(max_length=128)
    data_type = models.SmallIntegerField(default =0,choices = DATAITEM_DATATYPE)
    ...

模型A的序列化器

class AssetModelSerializer(serializers.ModelSerializer):
    org =  serializers.SlugRelatedField(queryset=Org.objects.all(), slug_field='name')
    class Meta:
        model = AssetModel
        fields = ('org', 'name', 'model_type',..

模型B的序列化器

class DataitemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Dataitem
        fields = ('mod', 'name','data_type'...)

Model A 的主键只是 Django 自动添加的 id。序列化模型B时,需要获取模型A的组织和名称,读写都需要。

【问题讨论】:

标签: python django rest


【解决方案1】:

嵌套序列化器

您可以这样做,为Dataitem 定义一个序列化器,它可以重用AssetModel 模型的序列化器

class AssetModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = AssetModel

    # Fields org and name of AssetModel will be inlcuded by default

class DataitemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Dataitem

    mod = AssetModelSerializer()
        # This is the Dataitem.mod field
        # which is a FK to AssetModel,
        # Now it'll be serilized using the AssetModelSerializer
        # and include the org and name fields of AssetModelSerializer

我更喜欢这种方法,因为我得到了控制。 如果你使用上面的序列化你会得到这样的结构:

data_item = {'name': ..., 'mod': {'org': ..., 'name': ...}}
                          ^
                          |___ AssetModel fields

或者你也可以使用depth = n

你也可以在Dataitem中使用depth = 1

class DataitemSerializer(serializers.ModelSerializer):
        class Meta:
            model = Dataitem
            depth = 1 # Will include fields from related models
                      # e.g. the mod FK to AssetModel

可写嵌套序列化器

因为嵌套创建和更新的行为可能不明确, 并且可能需要相关模型、REST 之间的复杂依赖关系 框架 3 要求您始终明确地编写这些方法。

我们必须实现create/update 以使其可按照DRF's documentation 写入

class DataitemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Dataitem

    # Nested serializer
    mod = AssetModelSerializer()

    # Custom create()
    def create(self, validated_data):
        # First we create 'mod' data for the AssetModel
        mod_data = validated_data.pop('mod')
        asset_model = AssetModel.objects.create(**mod_data)

        # Now we create the Dataitem and set the Dataitem.mod FK
        dataitem = Dataitem.objects.create(mod=asset_model, **validated_data)

        # Return a Dataitem instance
        return dataitem

【讨论】:

  • AssetModel中还有其他字段,我不想序列化。要使用嵌套序列化程序,我是否必须定义一个仅包含 org 和 name 字段的新序列化程序?
  • 是的,只需像你一样使用fields = (...)
  • 非常感谢。但看起来 mod 字段上的写入会失败。
  • 没问题!我会尝试获取最新版本的 DRF 并阅读有关可写嵌套序列化程序django-rest-framework.org/api-guide/serializers/…
  • @ThomasLiu 不客气。我添加了一个示例,以便您可以与您的模型相关联。请注意,此示例适用于 1 个嵌套模型,但如果 AssetModel 本身需要 FK 键,您将不得不从 validated_data 解压缩更多数据并创建对象、链接 FK 等。我建议您使用简单的 1 嵌套来练习这个先做模型。我希望这能让你走上正轨。如果对您有帮助,请投票/接受答案!谢谢!
【解决方案2】:

似乎有一个图书馆可以做到这一点 drf-writable-nested

它处理这些类型的创建和序列化

  • OneToOne(直接/反向)
  • 外键(直接/反向)
  • ManyToMany(直接/反向,不包括与直通模型的 m2m 关系)
  • GenericRelation(这始终只是反向)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 2023-01-10
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 2016-05-29
    相关资源
    最近更新 更多