Я пытаюсь написать полевой сериализатор для моего API django, который передает null
пользовательскому методу .to_internal_value
.
Мой вариант использования для двух datetime
полей, которые составляют диапазон времени. Я хочу, чтобы пользователь моего API мог дать мне что-то вроде "start_dt": null
в запросе PUT / POST / PATCH, и чтобы мой сериализатор перевел это в datetime.datetime.min
(или, в случае end_dt
, datetime.datetime.max
).
Вот что у меня есть. Я могу заставить сериализацию Object->JSON
работать хорошо (переводит значения datetime.min
и datetime.max
в None
), используя метод .to_representation(self, value)
- однако он не вызывает .to_internal_value(self, value)
при преобразовании из null->None
- и вместо этого передает None
остальной части моей логики всякий раз, когда одно из двух полей задается как null
.
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.min
и datetime.max
.
EX 3:
Публикация этого
{
"start_dt": "2018-08-28T00:00:00Z",
"end_dt": null
}
Кажется, для вызова to_internal_value
- но только для start_dt
(который он правильно разрешает в объект datetime). Он не вызывает to_internal_value
на null
.