Django序列化器:如何验证模型实例?

时间:2018-09-13 08:26:45

标签: python django django-rest-framework django-serializer

我对Django序列化器还很陌生,但仍然对它们的工作方式感到困惑。

我有一个相当普遍的场景,其中我在调用api,该api只是在模型对象中设置一个字段并保存它(假设记录已经存在并且正在被更新)。但是,我需要在保存之前验证此模型对象。

api.py

@detail_route(methods=['POST'], url_path='submit-draft')
def submit_draft(self, request, *args, **kwargs):
    booking = self.get_object()

    // serializer with custom validations.
    serializer = self.get_serializer(booking)
    serializer.is_valid(raise_exception=True)

    booking.submit_draft(by=request.user)
    booking.save()

    data = serializers.BookingDetailSerializer(booking, context={'request': request}).data

    return response.Ok(data)

serializers.py

class BookingCreateUpdateSerializer(serializers.ModelSerializer):
    date = serializers.CharField()

    duration = serializers.IntegerField(required=True, )

    created_by = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault(), )

    modified_by = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault(), )
    ....

    class Meta:
    model = models.Booking
        fields = [
        'title',
        'date',
        'duration',
        'client',
        'created_by',
        'modified_by',
        ....
    ]

但是,出现此错误:

AssertionError: Cannot call '.is_valid()' as no 'data=' keyword argument was passed when instantiating the serializer instance.

我知道序列化程序期望使用字典而不是实际的模式对象。但是我不知道如何实现我想要的目标。验证模型对象。有人可以建议正确的方法吗?

2 个答案:

答案 0 :(得分:3)

您可以使用序列化程序:

1)将对象序列化为字典。在这种情况下,您不需要调用is_valid,因为该对象已经创建并且具有有效值。因此,您可以执行以下操作:

serializer = BookingCreateUpdateSerializer(booking)

return Response(serializer.data)

2)序列化输入并使用序列化器创建新对象。在这种情况下,输入是一个字典,在调用保存之前需要首先对其进行验证。您可以执行以下操作:

serializer = BookingCreateUpdateSerializer(data=input_dict)
serializer.is_valid()
serializer.save()

更新以回答评论

您可以执行以下操作以使用序列化程序更新实例:

serializer = BookingCreateUpdateSerializer(booking, data=input_data_to_update, partial=True)
serializer.is_valid()

instance = serializer.save()

# and serialize the updated instance for response using another serializer
output_data = BookingDetailSerializer(instance).data

答案 1 :(得分:0)

这是花了将近一天的时间挠挠我的头才终于起作用的方法。

api.py

@detail_route(methods=['POST'], url_path='submit-draft')
def submit_draft(self, request, *args, **kwargs):
    // Step1. Get current model instance.
    booking = self.get_object()

    // Step2. Serialize the model instance using same serializer as in Step5.
    booking_data = serializers.BookingDetailSerializer(booking, context={'request': 
    request}).data

    // Step3. Deserialize the data from Step2 (using `BookingCreateUpdateSerializer` serializer 
    as mentioned in description and check for validations.
    serializer = self.get_serializer(data=booking_data)
    serializer.is_valid(raise_exception=True)       

    // Step4. If no validation error, set the required field and save the instance.
    booking.submit_draft(by=request.user)
    booking.save()

    // Step5. Return response.
    data = serializers.BookingDetailSerializer(booking, context={'request': request}).data

    return response.Ok(data)

我今天学到了更多有关串行器的知识。我们可以将模型实例传递到不同的序列化器中,并根据我们的要求更改其形状。