我正在使用Django REST Framework,特别是ModelSerializer
实例,以接收一些日期/时间信息,以及其他字段。在我的视图中POST或PUT的Django表单使用单个字段表示日期,单独的字段表示小时,分钟和上午/下午。
我编写了一个函数来处理将值重新组合到Python日期时间对象中,但由于某种原因,当我的函数返回正确的日期时间时,当日期时间被分配回时,时间部分变为零。用于保存的序列化程序对象。
我是DRF的新手,所以也许我只需要完全采用另一种方法......
def roomeventrequest(request, roomevent_id):
"""
THIS IS THE VIEW
"""
...
elif request.method == 'PUT':
data = JSONParser().parse(request)
roomevent = RoomEvent.objects.get(pk=roomevent_id)
serializer = RoomEventSerializer(roomevent, data=data)
if serializer.is_valid():
serializer.data['start_datetime'] = _process_datetime(serializer.validated_data['start_datetime'],
data['start_hour'],
data['start_min'],
data['start_ampm'])
serializer.data['end_datetime'] = _process_datetime(serializer.validated_data['start_datetime'],
data['end_hour'],
data['end_min'],
data['start_ampm'])
print (serializer.data['start_datetime'])
print (serializer.data['end_datetime'])
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
def _process_datetime(date_obj, hour, minute, ampm):
print (date_obj)
if ampm == 'am' and hour == 12:
hour = 0
elif ampm == 'pm':
hour += 12
return_date = date_obj.replace(minute=int(minute), hour=int(hour))
print(return_date)
return return_date
以上内容从print
语句输出以下内容:
2015-05-21 00:00:00
2015-05-21 08:00:00
2015-05-21 00:00:00
2015-05-21 09:00:00
2015-05-21T00:00:00
2015-05-21T00:00:00
为什么结果时间部分是空白的?我在哪里偏离轨道?
答案 0 :(得分:1)
您遇到的问题是您正在从外部修改序列化数据,而这些数据实际上并未传播到内部使用的数据。因此,即使您要更改start_datetime
和end_datetime
字段,内部DRF仍会看到仅包含日期的datetime
个对象。
您有几个选择
serializer.validated_data
(而不是serializer.data
)。这是传递给create
和update
。我建议现在避免使用#3,因为validated_data
字典设计为只读,并且可能在将来强制执行。因此,您只需要#1和#2,这两项工作都需要修改代码的不同部分,并在不同情况下更好地工作。
如果您的验证需要将错误返回到需要匹配特定字段的前端,而不是仅仅评论错误的日期格式,则第一个选项最有效。但它还需要创建一个用于在所有字段中进行验证的自定义MultipartDatetimeSerializer
。
from datetime import date, datetime, time
class MultipartDatetimeSerializer(serializers.Serializer):
date = serializers.DateField()
hour = serializers.IntegerField(
min_value=1,
max_value=12
)
minute = serializers.IntegerField(
min_value=0,
max_value=59,
)
period = serializers.ChoiceField(
choices=(
('am', 'A.M.', ),
('pm', 'P.M.', ),
)
)
def to_internal_value(self, data):
parsed_data = super(MultipartDatetimeSerializer, self).to_internal_value(data)
hour = parsed_data['hour']
if parsed_data['period'] == 'pm':
hour += 12
elif hour == 12:
hour = 0
time_data = time(
hour=hour,
minute=parsed_data['minute']
)
return datetime.combine(
date=parsed_data['date'],
time=time_data
)
def to_representation(self, instance):
"""
Convert a datetime to a dictionary containing the
four different fields.
The period must be manually determined (and set), so there
is some pre-processing that has to happen here.
"""
obj = {
"date": instance.date,
"hour": instance.hour,
"minute": instance.minute,
}
if obj["hour"] > 12:
obj["hour"] -= 12
obj["period"] = 'pm'
else:
if obj["hour"] == 0:
obj["hour"] = 12
obj["period"] = 'am'
return super(MultipartDatetimeSerializer, self).to_representation(obj)
此序列化程序现在可用于将datetime
拆分为date
,hour
,minute
和period
组件。
obj = datetime.now()
serializer = MultipartDatetimeSerializer(obj)
print(serializer.data)
将它们组合在一起
data = {
"date": "2015-01-01",
"hour": "11",
"minute": "59",
"period": "pm",
}
serializer = MultipartDatetimeSerializer(data=data)
if serializer.is_valid():
print(serializer.to_internal_value(serializers.validated_data))
else:
print(serializer.errors)
如果您只需要返回一个错误,说明所给出的数据不是实际日期,则第二个选项效果最佳。您可以找到与输入内容非常匹配的a date format,然后连接传入的数据以匹配该数据。
在您的情况下,最接近的日期格式显示为%Y-%m-%d %I:%M %p
,与2015-01-01 11:59 PM
之类的日期相匹配。
因此,剩下的就是在序列化器上设置日期字段的日期格式以接受上述格式(以及ISO 8601,默认值),这就像设置input_formats
一样简单
['iso-8601', '%Y-%m-%d %I:%M %p']
更改传递给序列化程序的数据以连接传入值以匹配字段
data = JSONParser().parse(request)
data['start_datetime'] = "%s %s:%s %s" % (data['start_datetime'], data['start_hour'], data['start_min'], data['start_ampm'], )
data['end_datetime'] = "%s %s:%s %s" % (data['end_datetime'], data['end_hour'], data['end_min'], data['end_ampm'], )
请注意,我总是使用%s
修饰符而不是%d
修饰符,因为DRF可以处理传递到字段中的错误数字,并且它可以防止在处理时发生未处理的异常字符串传入。