drf 高级三验证

时间:2023-02-15 17:22:39

drf验证

is_valid

反序列化时,始终需要验证is_valid(),否则将抛出异常。如果发生任何验证错误(serializers.ValidationError),.errors属性可以获取错误字典。字典里的每一个键都是字段名称,值是与该字段对应的任何错误消息的字符串列表。non_field_errors键可能存在,它将列出任何一般验证错误信息。non_field_errors的名称可以通过REST framework设置中的NON_FIELD_ERRORS_KEY来自定义。 当对对象列表进行序列化时,返回的错误是每个反序列化项的字典列表。

serializer = CommentSerializer(data={})
serializer.is_valid()
# False
serializer.errors

输出结果,

{
    "name": [
        "该字段不能为空。"
    ],
    "price": [
        "请填写合法的数字。"
    ],
    "description": [
        "该字段不能为空。"
    ],
    "release_date": [
        "日期格式错误。请从这些格式中选择:YYYY-MM-DD。"
    ]
}

并且is_valid有一个参数raise_exception默认为False。如果使用默认值,验证失败继续保存将直接抛出异常。如果为True异常将被drf默认异常'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'所捕获处理后返回给前端。

def exception_handler(exc, context):
    """
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    """
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()

    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    return None

基础序列化器

from rest_framework import serializers

class BaseSerializer(serializers.Serializer):
    email = serializers.EmailField(required=False)
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

字段级别认证

通过Serializer中添加validate_<field_name>方法来指定自定义字段级别的验证。验证失败抛出serializers.ValidationError后被exception_handler捕获。

class CommentSerializer(BaseSerializer):
    @staticmethod
    def validate_content(value):
        """
        Check that the blog post is about Django.
        """
        if len(value) < 20:
            raise serializers.ValidationError("你太短了")
        return value
# 返回结果
# {
#    "content": [
#         "你太短了"
#    ]
# }

对象级别的验证

要执行需要访问多个字段的任何其他验证,请添加一个validate方法到Serializer子类中。这个方法采用字段值字典的单个参数,如果需要应该抛出一个 ValidationError异常,或者只是返回经过验证的值。

class CommentSerializer(BaseSerializer):

    def validate(self, attrs):

        if not attrs['email']:
            raise serializers.ValidationError("邮箱不能为空")
        return attrs

验证器

序列化器上的各个字段都可以包含验证器,通过在字段实例上声明

def verify_email(value):
    if not value:
        raise serializers.ValidationError("邮箱不能为空")

class BaseSerializer(serializers.Serializer):
    email = serializers.EmailField(required=False, validators=[verify_email])
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

额外的上下文参数

在序列化器中若何使用rest_framework 中 request。最原始的方式是手动通过Serializer(xx, context={'request': request})传递。或者高级API提供这个能力GenericAPIView及以上,get_serializer_context更加方便做一些操作。