Django Rest Framework没有对嵌套数据

时间:2016-12-20 17:42:28

标签: django-rest-framework

我无法让DRF允许在一个序列化程序中提供嵌套数据的read_only版本和仅列表中的id的可写版本。这对我来说感觉像是一个错误,但通常这意味着我不能很好地理解框架,并被错误信息误导。

class Individual(models.Model):
  household = models.ForeignKey(
      'household.Household',
      null=True,
      related_name="individuals")
  name = models.CharField(
      max_length=100, default='')

class Household(models.Model):
    address_line1 = models.CharField(max_length=64, default='')

class IndividualListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Individual
        depth = 0
        fields = ('url', 'id', 'name', 'household')
        read_only_fields =  fields

class HouseholdUpdateSerializer(serializers.ModelSerializer):
    individuals_details = IndividualListSerializer(many=True, source='individuals', read_only=True)
    class Meta:
        model = Household
        fields = ('id', 'address_line1', 'individuals', 'individuals_details')
        read_only_fields = ('id', 'individuals_details')

错误以

的形式返回
AssertionError: The `.update()` method does not support writable nested fields by default. Write an explicit `.update()` method for serializer `household.serializers.HouseholdUpdateSerializer`, or set `read_only=True` on nested serializer fields. // Werkzeug Debugger</title>

我在嵌套字段上使用了read_only(在更新响应中需要)。但错误仍然表明我没有这样做。

如果我完全删除individuals字段,individuals_details会返回没有错误的可读数据,但由于它忽略了正在发送的individuals数据,因此它不会更新该列表。

如果我删除individuals_details字段,DRF会接受individuals列表并对模型执行更新。但是那时所需的返回数据不存在。

因此,虽然读取嵌套或写入列表可以自行工作,但是当添加另一个时,序列化器不起作用。

这似乎是人们陷入困境的一个相当普遍的领域,似乎答案this SO question已成为模式的最佳实践。但由于某种原因,它在我的代码中不起作用。也许是因为我的模型中的ManyToOne。

我可以解决这个问题,方法是更改​​客户端以执行更新的PUT,忽略响应,然后执行单独的GET,但这很草率,如果可以使DRF更新工作则不需要如预期的那样。

我在这里错过了什么?

1 个答案:

答案 0 :(得分:1)

你问几个问题所以我将从表示开始。实际上,对于完整Individual视图,您不需要单独的字段,您可以只使用to_representation方法。

class HouseholdUpdateSerializer(serializers.ModelSerializer):

    class Meta:
        model = Household
        fields = ('id', 'address_line1', 'individuals')

    def to_representation(self, instance):
        representation = super(HouseholdUpdateSerializer, self).to_representation(instance)
        representation['individuals'] = IndividualListSerializer(instance.individuals.all(), many=True).data
        return representation

通常,当您需要模型的更新相关字段时,您应该覆盖createupdate序列化方法。

class HouseholdUpdateSerializer(serializers.ModelSerializer):
    ....
    def update(instance, validated_data):
        # get and remove individuals from validated_data
        individuals = validated_data.pop('individuals') 
        # delete all related links to individuals
        # You could provide some validation before clear, check if provided pks exists in db table
        instance.individuals.clear() 
        # update related links with new individuals
        instance.individuals.add(*individuals) 
        # call super to provide update for other fields
        return super(HouseholdUpdateSerializer, self).update(validated_data)  

create可能在您的情况下运行良好而不会覆盖。如果它不只是写它类似于update