【问题标题】:Nested serializer with optional field raising KeyError带有可选字段引发 KeyError 的嵌套序列化程序
【发布时间】:2017-01-02 13:49:57
【问题描述】:

我有两个序列化器,第一个(有点简化):

class FilterSerializer(serializers.Serializer):
    brand = serializers.PrimaryKeyRelatedField(
        queryset=org_models.Brand.objects, many=False,
        error_messages={'does_not_exist': org_consts.BRAND_NOT_EXIST}
    )

    country = serializers.PrimaryKeyRelatedField(
        queryset=org_models.Country.objects, many=False,
        error_messages={'does_not_exist': org_consts.COUNTRY_NOT_EXIST}
    )

    level = serializers.PrimaryKeyRelatedField(
        queryset=org_models.Level.objects, many=False, required=False,
        error_messages={'does_not_exist': org_consts.DISTRICT_NOT_EXIST}
    )

    class Meta:
        fields = ('brand', 'country', 'level')

第二个:

class PeopleReportSerializer(serializers.Serializer):
    filters = FilterSerializer(many=True)
    start_date = serializers.DateField(required=False)
    end_date = serializers.DateField(required=False)

    class Meta:
        fields = ('filters', 'start_date', 'end_date')

    def validate(self, data):
        """Check if end_date occurs after start_date.
        """
        if data.get('start_date') and data.get('end_date'):
            if data['start_date'] > data['end_date']:
                raise serializers.ValidationError(constants.INVALID_START_DATE)
        return data

为了清楚起见,我删除了一些字段。 所以基本上我想要从这个序列化程序中验证数据库中是否存在具有发布 ID 的对象。在 GET 上,我希望它根据 request.user 返回一些数据,但这是另一种情况。

所以现在在我看来,我正在做这样的事情:

class PeopleReportView(ReportsPermissionMixin, views.APIView):
    serializer_class = PeopleReportSerializer
    task = staticmethod(people_report)  # celery task, creates reports

    def get(self, request):
        # TODO: depending on request.user return initial data such as:
        # country / brand / district and so on
        return Response()

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid(raise_exception=True):
            task = self.task.apply_async(kwargs=serializer.data)
            return Response({'task_id': task.id})

我的问题是,当我发布没有level 字段(这不是必填字段)的数据时,我得到KeyError: 'level'FilterSerializer 工作正常,但嵌套时出现此错误。 显然我错了,我的测试没有测试data 属性,只测试@987654328 @方法。

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    尝试改用allow_null 标志:

     level = serializers.PrimaryKeyRelatedField(
        queryset=org_models.Level.objects, many=False, allow_null=True,
        error_messages={'does_not_exist': org_consts.DISTRICT_NOT_EXIST}
    )
    

    代替:

     level = serializers.PrimaryKeyRelatedField(
        queryset=org_models.Level.objects, many=False, required=False,
        error_messages={'does_not_exist': org_consts.DISTRICT_NOT_EXIST}
    )
    

    更多信息请参见here

    【讨论】:

      【解决方案2】:

      尽管PrimaryKeyRelatedFieldField,但在使用required=False 初始化时,它的工作方式并不相同。就像 Remi 写的一样,当前版本的 DRF (3.5.X) 支持读/写字段的唯一方法是在这些字段上allow_null(除了使用一些奇怪的解决方法)。

      API 必须发送一个空字段,并且在对象表示中 Serializer.data 这个字段将有一个 None 值。因为在我的情况下,我不能有 None 值,所以我修改了 Serialzier.to_representation 方法,如下所示:

      def to_representation(self, instance):
              """Excludes fields with None value from representation
              """
              ret = super().to_representation(instance)
              return {field: value for (field, value) in ret.items()
                      if value is not None}
      

      【讨论】:

        猜你喜欢
        • 2021-07-11
        • 2022-12-12
        • 1970-01-01
        • 2016-02-26
        • 1970-01-01
        • 2012-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多