【问题标题】:Django Serializer: How can I validate a model instance?Django Serializer:如何验证模型实例?
【发布时间】:2018-09-13 08:26:45
【问题描述】:

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

我有一个相当普遍的场景,其中我正在调用我的 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.

我知道序列化程序需要一个字典而不是实际的模态对象。但我不知道如何实现我想要的。验证模型对象。谁能建议正确的方法?

【问题讨论】:

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


【解决方案1】:

您可以使用序列化程序:

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

serializer = BookingCreateUpdateSerializer(booking)

return Response(serializer.data)

2) 使用序列化器序列化输入并创建新对象。在这种情况下,输入是一个字典,在调用 save 之前需要先验证它。你可以这样做:

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) serialize your object to a dictionary. In this case, you dont need to call is_valid as the object has been already created and it has valid values. So you do: 我有一种情况,在第一次创建记录时,我有一组不同的验证(使用不同的序列化程序),但在更新它时,我使用的是不同的序列化程序具有不同的验证集。 (想象一个草稿记录和一个完全填写的记录)所以这可能行不通,因为它仍然需要验证。
  • 2) serialize an input and create new object. In this case, input is a dictionary and it needs to be validated first before calling save. So you do: 如何将我的模态实例Booking 转换为input_dict
  • 它是序列化器的数据属性,它返回一个 ReturnDict 。您只需要指定序列化程序的字段即可返回您想要获取的模型的字段。您可以使用一种序列化程序进行创建,另一种进行更新(可以有不同的字段)。
  • 嗯...我不明白。你能检查我的api方法并修改它吗?如您所见,我在返回纯粹用于查看目的的数据时使用了单独的序列化程序:BookingDetailSerializer。我必须使用给定的序列化程序:BookingCreateUpdateSerializer 来验证和保存实例。所以我不确定它会如何以相同的方法工作。
  • 没有data=input_data_to_update。我只需要验证模型实例并设置一个字段 (booking.submit_draft(by=request.user))。无论如何,感谢所有的帮助。终于想出了解决办法,写在这里。
【解决方案2】:

在我摸索了将近一天之后,这终于奏效了。

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)

我今天学到了更多关于序列化程序的知识。我们可以将模型实例传递给不同的序列化器,并根据我们的要求改变它的形状。

【讨论】:

  • Python 对 cme​​ts 使用 #,而不是 //
  • oops :P Java 开发人员,最近转换到 python。
猜你喜欢
  • 2017-03-04
  • 2017-10-30
  • 2021-11-03
  • 2020-03-05
  • 2014-07-14
  • 2021-07-15
  • 2017-08-16
  • 2020-12-25
  • 1970-01-01
相关资源
最近更新 更多