首页 > 解决方案 > Django Rest Framework - 在空值上调用 serializer.to_internal_value

问题描述

我正在尝试为传递null给自定义.to_internal_value方法的 django API 编写字段序列化器。

我的用例是用于datetime构成时间范围的两个字段。我希望我的 API 的用户能够"start_dt": null在 PUT/POST/PATCH 请求中给我一些东西,并让我的序列化程序将其转换为datetime.datetime.min(或者,在 , 的情况下end_dtdatetime.datetime.max

这是我到目前为止所拥有的。我能够使用该方法使Object->JSON序列化正常工作(转换datetime.mindatetime.max值到None) - 但是在转换时.to_representation(self, value)它似乎没有调用- 而是在两个字段之一被指定为时传递到我的逻辑的其余部分。.to_internal_value(self, value)null->NoneNonenull

import pytz
from datetime import datetime

UTC = pytz.timezone("UTC")
max_dt = UTC.localize(datetime.max)
min_dt = UTC.localize(datetime.min)

class CustomDateTimeField(serializers.Field):

    def __init__(self, *args, **kwargs):

        self.datetime_field = fields.DateTimeField()

        self.infinity_direction = kwargs.pop('infinity_direction', None)
        if not (self.infinity_direction == '+' or self.infinity_direction == '-'):
            raise AssertionError("Expected CustomDateTimeField to be created with `infinity_direction` equal to either '+' or '-'")

        super().__init__(*args, **kwargs)

    def to_representation(self, value):
        """
        Represent both MAX and MIN times as None/'null'
        Else return a normal datetime string
        """

        if value == min_dt or value == max_dt:
            return None

        return self.datetime_field.to_representation(value)


    def to_internal_value(self, value):
        """
        Translate None/'null' values to either MAX or MIN - depending on self.infinity_direction
        Else return a normal datetime object
        """

        if value == None:
            return max_dt if self.infinity_direction == '+' else min_dt

        return self.datetime_field.to_internal_value(value)

在我的模型的序列化程序中,我使用了这些字段,例如...

class TimeRangeSerializer(serializers.ModelSerializer):

    start_dt = CustomDateTimeField(infinity_direction='-', allow_null=True)
    end_dt = CustomDateTimeField(infinity_direction='+', allow_null=True)

    class Meta:
        model = TimeRange
        fields = ('id', 'start_dt', 'end_dt')

提供更多示例...

EX 1: 发布这个

{}

给出以下正确的返回值

{
    "end_dt": [
        "This field is required."
    ],
    "start_dt": [
        "This field is required."
    ]

}

例 2:

发布这个

{
    "start_dt": null,
    "end_dt": null
}

CustomDateTimeField.to_internal_value永远不会被调用 - 并被start_dt传递end_dt给我的对象的创建None,而不是期望的datetime.mindatetime.max值。

例 3:

发布这个

{
    "start_dt": "2018-08-28T00:00:00Z",
    "end_dt": null
}

似乎调用to_internal_value- 但仅限于start_dt(它正确解析为日期时间对象)。它不调用to_internal_value.null

标签: pythondjangoserializationdjango-rest-frameworkdeserialization

解决方案


更改您的代码如下:

def to_internal_value(self, value):
    """
    Translate None/'null' values to either MAX or MIN - depending on self.infinity_direction
    Else return a normal datetime object
    """

    return self.datetime_field.to_internal_value(value)

def validate_empty_values(self, data):
    (is_empty_value, data) = super(CustomDateTimeField, self).validate_empty_values(data)

    if is_empty_value and data is None:
        return is_empty_value, max_dt if self.infinity_direction == '+' else min_dt

    return is_empty_value, data

to_interval_value如果字段的值为空,则drf 永远不会调用该字段。


推荐阅读