英文:
How to send multiple objects on serializers.Serializer (got non_field_errors)
问题
我正在尝试通过创建视图集方法将多个数据发送到序列化器。但是在这样做时,我收到以下错误:
我在序列化器中使用了许多属性,但我仍然收到相同的错误。我是这样发布数据的:
[
{
"weekday": "day",
"start_time": "time",
"end_time": "time"
},
{
"weekday": "day",
"start_time": "time",
"end_time": "time"
}
]
这是视图集和序列化器的代码:
viewset.py
class SpecialistAvailabilityView(viewsets.ModelViewSet):
model = SpecialistAvailability
permission_classes = [IsAuthenticated, IsSpecialist]
def get_serializer_class(self):
saving_actions = ["create", "update", "partial_update"]
if self.action in saving_actions:
return WeekDayTimeSerializer
return SpecialistAvailabilitySerializer
def get_queryset(self):
queryset = SpecialistAvailability.objects.filter(
specialist__user=self.request.user
).order_by('-start_time__week_day')
return queryset
def translate_availability(self, data):
pass
def create(self, request, *args, **kwargs):
serializer = WeekDayTimeSerializer(data=request.data, many=isinstance(request.data, list))
print(serializer.initial_data)
print(serializer.is_valid())
if serializer.is_valid():
self.translate_availability(serializer.validated_data)
return super().create(request, *args, **kwargs)
serializer.py
import pytz
from datetime import datetime
from rest_framework import serializers
from apps.specialist.models.specialist_availability import SpecialistAvailability
from apps.specialist.utils import WEEKDAYS
class WeekDayTimeSerializer(serializers.Serializer):
weekday = serializers.ChoiceField(choices=WEEKDAYS, required=True)
start_time = serializers.TimeField()
end_time = serializers.TimeField()
# TODO 添加时间和星期几检查
# 开始时间必须小于结束时间
# 如果有多个,只能发送一天
def validate(self, attrs):
self.validate_start_time(attrs['start_time'])
self.validate_start_time(attrs['end_time'])
self.validate_end_time
return super().validate(attrs)
def validate_start_time(self, start_time):
try:
datetime.strptime(start_time, "%H:%M")
except:
raise serializers.ValidationError("错误的时间格式")
return start_time
def validate_end_time(self, end_time):
try:
datetime.strptime(end_time, "%H:%M")
except:
raise serializers.ValidationError("错误的时间格式")
return end_time
class SpecialistAvailabilitySerializer(serializers.ModelSerializer):
class Meta:
model = SpecialistAvailability
fields = ['id', 'specialist', 'start_time', 'end_time']
def to_representation(self, instance):
localized_start_time = self.set_time_to_local(instance.start_time)
localized_end_time = self.set_time_to_local(instance.end_time)
data = {
'availability': {
'id': instance.id,
'start_day': localized_start_time.strftime('%A'),
'start_day_code': localized_start_time.isoweekday(),
'start_time': localized_start_time.time(),
'end_day': localized_end_time.strftime('%A'),
'end_day_code': localized_end_time.isoweekday(),
'end_time': localized_end_time.time()
}
}
return data
def validate(self, attrs):
instance = getattr(self, 'instance', None)
if instance:
attrs['id'] = instance.id
specialist_availability = self.Meta.model(**attrs)
specialist_availability.clean()
super().validate(attrs)
attrs['start_time'] = self.set_time_to_utc(attrs['start_time'])
attrs['end_time'] = self.set_time_to_utc(attrs['end_time'])
return attrs
def set_time_to_local(self, time):
request_user = self.context['request'].user
user_tz = request_user.timezone
if user_tz == pytz.utc:
return time
unlocalized_time = time.replace(tzinfo=None)
utc_time = pytz.utc.localize(unlocalized_time)
local_time = utc_time.astimezone(user_tz)
return local_time
def set_time_to_utc(self, time):
request_user = self.context['request'].user
user_tz = request_user.timezone
if user_tz == pytz.utc:
return time
unlocalized_time = time.replace(tzinfo=None)
local_time = user_tz.localize(unlocalized_time)
utc_time = local_time.astimezone(pytz.utc)
return utc_time
英文:
I'm trying to send multiple data through a create viewset method to a serializer. However when doing that I get an error as follows:
Im using many attribute into the serializer, but I sill get the same error. I'm posting data like this:
[
{
"weekday":"day",
"start_time":"time",
"end_time":"time"
},
{
"weekday":"day",
"start_time":"time",
"end_time":"time"
}
]
This is the viewset and serializer code:
viewset.py
class SpecialistAvailabilityView(viewsets.ModelViewSet):
model = SpecialistAvailability
permission_classes = [IsAuthenticated, IsSpecialist]
def get_serializer_class(self):
saving_actions = ["create", "update", "partial_update"]
if self.action in saving_actions:
return WeekDayTimeSerializer
return SpecialistAvailabilitySerializer
def get_queryset(self):
queryset = SpecialistAvailability.objects.filter(
specialist__user=self.request.user
).order_by('-start_time__week_day')
return queryset
def translate_availability(self, data):
pass
def create(self, request, *args, **kwargs):
serializer = WeekDayTimeSerializer(data=request.data, many=isinstance(request.data, list))
print(serializer.initial_data)
print(serializer.is_valid())
if serializer.is_valid():
self.translate_availability(serializer.validated_data)
return super().create(request, *args, **kwargs)
serializer.py
import pytz
from datetime import datetime
from rest_framework import serializers
from apps.specialist.models.specialist_availability import SpecialistAvailability
from apps.specialist.utils import WEEKDAYS
class WeekDayTimeSerializer(serializers.Serializer):
weekday = serializers.ChoiceField(choices=WEEKDAYS, required=True)
start_time = serializers.TimeField()
end_time = serializers.TimeField()
# TODO ADD TIME AND WEEKDAY CHECKING
# START TIME MUST BE LESS THAN END TIME
# JUST ONE DAY MUST BE SENDED IF MANY
def validate(self, attrs):
self.validate_start_time(attrs['start_time'])
self.validate_start_time(attrs['end_time'])
self.validate_end_time
return super().validate(attrs)
def validate_start_time(self, start_time):
try:
datetime.strptime(start_time, "%H:%M")
except:
raise serializers.ValidationError("Wrong time format")
return start_time
def validate_end_time(self, end_time):
try:
datetime.strptime(end_time, "%H:%M")
except:
raise serializers.ValidationError("Wrong time format")
return end_time
class SpecialistAvailabilitySerializer(serializers.ModelSerializer):
class Meta:
model = SpecialistAvailability
fields = ['id', 'specialist', 'start_time', 'end_time']
def to_representation(self, instance):
localized_start_time = self.set_time_to_local(instance.start_time)
localized_end_time = self.set_time_to_local(instance.end_time)
data = {
'availability': {
'id': instance.id,
'start_day': localized_start_time.strftime('%A'),
'start_day_code': localized_start_time.isoweekday(),
'start_time': localized_start_time.time(),
'end_day': localized_end_time.strftime('%A'),
'end_day_code': localized_end_time.isoweekday(),
'end_time': localized_end_time.time()
}
}
return data
def validate(self, attrs):
instance = getattr(self, 'instance', None)
if instance:
attrs['id'] = instance.id
specialist_availability = self.Meta.model(**attrs)
specialist_availability.clean()
super().validate(attrs)
attrs['start_time'] = self.set_time_to_utc(attrs['start_time'])
attrs['end_time'] = self.set_time_to_utc(attrs['end_time'])
return attrs
def set_time_to_local(self, time):
request_user = self.context['request'].user
user_tz = request_user.timezone
if user_tz == pytz.utc:
return time
unlocalized_time = time.replace(tzinfo=None)
utc_time = pytz.utc.localize(unlocalized_time)
local_time = utc_time.astimezone(user_tz)
return local_time
def set_time_to_utc(self, time):
request_user = self.context['request'].user
user_tz = request_user.timezone
if user_tz == pytz.utc:
return time
unlocalized_time = time.replace(tzinfo=None)
local_time = user_tz.localize(unlocalized_time)
utc_time = local_time.astimezone(pytz.utc)
return utc_time
答案1
得分: 2
You have overridden the method create()
of viewsets.ModelViewSet
in the SpecialistAvailabilityView,
but after all, you just call the parent method super().create(request, *args, **kwargs)
. So, in fact, your own code in the method create()
does not apply.
At the same time, the parent create()
method always uses many=False
in the serializer call.
So, you just need to replace the row
return super().create(request, *args, **kwargs)
by
return Response(serializer.data, status=status.HTTP_201_CREATED)
英文:
You have overridden the method create()
of viewsets.ModelViewSet
in the SpecialistAvailabilityView,
but after all, you just call the parent method super().create(request, *args, **kwargs)
. So, in fact, your own code in the method create()
does not apply.
At the same time, the parent create()
method always uses many=False
in the serializer call.
So, you just need to replace the row
return super().create(request, *args, **kwargs)
by
return Response(serializer.data, status=status.HTTP_201_CREATED)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论