如何在serializers.Serializer上发送多个对象(出现了non_field_errors错误)

huangapple go评论47阅读模式
英文:

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:

Error message

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)

huangapple
  • 本文由 发表于 2023年6月9日 07:03:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436219.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定