【问题标题】:django-rest-framework PUT manytomany through modeldjango-rest-framework PUT manytomany through model
【发布时间】:2015-09-15 16:02:58
【问题描述】:

我有一个带有 m2m 关系的 Django 模型,它使用直通模型:

models.py

class ModelA(models.Model):
    name = models.CharField(max_length=64)

class ModelB(models.Model):
    name = models.CharField(max_length=64)
    other_models = models.ManyToManyField("ModelA", through="ModelC")

class ModelC(models.Model):
    model_a = models.ForeignKey("ModelA", related_name="link_to_model_a")
    model_b = models.ForeignKey("ModelB", related_name="link_to_model_b")
    some_other_info = models.TextField()
    class Meta:
        unique_together = ("model_a", "model_b", )

我想用 django-rest-framework 序列化这个:

serializers.py

class ModelCSerializer(ModelSerializer):
    class Meta:
        model = ModelC
        fields = ('id', 'model_a', 'model_b', 'some_other_info', )

class QModelBSerializer(ModelSerializer):
    class Meta:
        model = ModelB
        fields = ('id', 'other_models', )
    other_models = ModelCSerializer(many=True, required=False, source="link_to_model_b")

现在,对于现有模型,GET 正确显示:

{
  "id": 2,
  "name": "i am an instance of model_b",
  "other_models": [
    {"id": 1, "model_a": 1,"model_b": 2, "some_other_info":"here is some other info"}
  ],
}

但是,如果我尝试 PUT 一些数据,它会失败并出现 unique_together 错误。我认为将其作为 PUT 发送会导致更新(不应引发 unique_together 错误)而不是创建?这是 PUT 的代码:

views.py

class ModelBDetail(APIView):
    def put(self, request, pk, format=None):
        model = ModelB.objects.get(id=pk)
        serializer = ModelBSerializer(model, data=request.data, context={"request": request})
        if serializer.is_valid():  # THIS IS RETURNING FALSE
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

有什么想法吗?

【问题讨论】:

  • 您是否在发布时将 GET 结果放入?
  • @Ivan - 是的,没有变化。

标签: python django serialization django-rest-framework


【解决方案1】:

Django REST 框架文档指出,实现creates and updates for nested representations 由开发人员决定。

【讨论】:

    【解决方案2】:

    尽管@Ivan 关于编写我自己的创建和更新 fn 是正确的,但我看到的具体问题是嵌套序列化没有与之关联的实例属性。

    新代码如下所示:

    serializers.py

    class ModelBSerializer(ModelSerializer):
    
        ....
    
        def update(self, model_instance, validated_data):
            model_c_serializer = self.fields["other_models"]
    
            model_c_data = validated_data.pop(model_c_serializer.source, [])
    
            for key, value in validated_data.iteritems():
                setattr(model_instance, key, value)
            model_instance.save()
    
            model_c_serializer.update(model_instance.link_to_model_b.all(),
    model_c_data)
    
            return model_instance
    
    class ModelCSerializer(ModelSerializer):
    
        ...
    
        def to_internal_value(self, data):
    
            # this is as good a place as any to set the instance
            try:
                model_class = self.Meta.model
                self.instance = model_class.objects.get(pk=data.get("id"))
            except ObjectDoesNotExist:
                pass
    
            return super(ModelCSerializer, self).to_internal_value(data)
    

    基本上,我为嵌套序列化程序显式调用update,并且我还强制每个嵌套序列化程序检查传递给它们的数据以获取实例。

    【讨论】:

      猜你喜欢
      • 2021-09-20
      • 2013-10-11
      • 2017-01-15
      • 2013-07-05
      • 1970-01-01
      • 2019-04-01
      • 2020-07-08
      • 2013-03-30
      • 2014-06-15
      相关资源
      最近更新 更多