【问题标题】:Django (DRF): Serialize and deserialize a ManyToMany field differently?Django (DRF):以不同的方式序列化和反序列化 ManyToMany 字段?
【发布时间】:2016-08-17 13:08:34
【问题描述】:

习惯了从 Tastypie 过来的 Django Rest Framework,但是在涉及 ManyToMany 字段时遇到了问题。

当需要对字段进行序列化时,它首选包含其完整表示,这可以通过添加具有 many=True 和 read_only=True 的 ModelSerializer 轻松完成。问题是这会阻止我保存帐户字段,因为它现在显示为空白。

如果我尝试删除 read_only=True 我得到

TypeError: 'accounts' is an invalid keyword argument for this function

最好发送完整的表示,但仅在接收相关的 POST(创建)或 PUT(更新)时需要 ID。

发布:

{
    "profile" : "1",
    "accounts" : ["1"],
    "amount" : "101.00"
}

回应:

{
  "id": 92,
  "accounts": [],
  "date_by": null,
  "amount": "101.00",
  "shared": false,
  "profile": 1
}

获取:

[
  {
    "id": 45,
    "accounts": [
      {
        "account_local": {
          "id": 3,
          "last_balance": "100.00",
        },
        "type": "LocalAccount"
      }
    ],
    "date_by": null,
    "amount": "100.00",
    "shared": false,
    "profile": 1
  },]

目标序列化器

class GoalSerializer(serializers.ModelSerializer):
    accounts = AccountSerializer(many=True, read_only=True)

    class Meta:
        model = Goal

目标视图集

class GoalViewSet(GenericViewSet, mixins.RetrieveModelMixin, mixins.ListModelMixin, mixins.CreateModelMixin):
    serializer_class = GoalSerializer
    queryset = Goal.objects.none()

    def get_queryset(self):
        return Goal.objects.filter(profile=self.request.user)

帐户序列化器

class AccountSerializer(serializers.ModelSerializer):
    type = SerializerMethodField('get_account_class')

    class Meta:
        model = Account
        fields = ('account_local','account_external', 'type')
        depth = 1

    def get_account_class(self, obj):
        if isinstance(obj.get_actual(), LocalAccount):
            return obj.get_actual().__class__.__name__
        elif isinstance(obj.get_actual(), ExternalAccount):
            return obj.get_actual().get_actual().__class__.__name__
        else:
            return "Error"

    def to_representation(self, instance):
        data = super(AccountSerializer, self).to_representation(instance)

        if isinstance(instance.get_actual(), ExternalAccount): 
            serializer = ExternalAccountSerializerEMT(instance.account_external.get_actual())
            data['account_external'] = serializer.data

        return data

【问题讨论】:

  • 请看我的另一个回答here

标签: python django django-rest-framework


【解决方案1】:

我设法通过以下方式解决了这个问题:


  • def to_internal_value(self, data): return Account.objects.get(id=data)

  • 更改 AccountSerializer
  • 移除字段的只读属性

    accounts = AccountSerializer(many=True)

POST/PUT 时账号只需要 id,GET 时返回整个账号

【讨论】:

  • POST 和 PUT 多对多字段的创建始终必须使用自定义代码处理,有时它可能会有点脏。我经常不得不在序列化程序中编写自己的create()update()。您对这种情况的解决方案似乎非常简单而且可以。
  • 我确实必须添加保护以确保帐户实际上归个人资料所有,但除此之外......
猜你喜欢
  • 2022-12-11
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 2021-03-18
  • 2012-06-29
  • 2018-10-10
  • 1970-01-01
相关资源
最近更新 更多