djangorestframework的serializer怎么抛出自定义异常?

首先是视图函数view的代码
class SmsCodeView(GenericAPIView):

# parser_classes = [JSONParser, FormParser]  # 改成接受表单
serializer_class = serializers.ImageCodeCheckSerializer

def post(self, request):
    # 获取数据(image_code_id,text)mobile参数不用校验,因为是通过正则匹配路由,匹配不成功就不会进入到路由,所以不用验证mobile
    # 校验数据(通过image_code_id查询redis),由序列化器完成
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)

    mobile = request.data.get('mobile')
    # 生成验证码内容
    sms_code = '%d' % random.randint(100000, 999999)
    # 保存短信验证码与发送记录
    redis_conn = get_redis_connection('verify_codes')


    # 调用自己写的阿里云短信服务发送短信
    try:
        # send_sms = AliyunSms(settings.ACCESSKEYID, settings.ACCESSSECRET, settings.SIGNNAME)
        # result_code = send_sms.send_sms(mobile, sms_code, constants.SMS_CODE_TEMP_ID)
        result_code = 'OK'
        # 使用redis管道
        pl = redis_conn.pipeline()
        pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)  # 设置短信验证码内容redis记录
        pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)  # 设置短信验证码发送记录
        pl.execute()
    except Exception as e:
        sms_logger.error("发送短信验证码[异常][mobile:%s, message:%s]" % (mobile, e))
        return gen_response('发送短信验证码异常', status=1, response_status=500)
    else:
        if result_code == 'OK':
            sms_logger.info("发送短信验证码[正常][mobile:%s]" % mobile)
            return gen_response('短信验证码发送成功,手机号{},验证码{}'.format(mobile, sms_code))
            # return Response({'message': '手机号{},验证码{}'.format(mobile, sms_code)})
        elif result_code == 'isv.DAY_LIMIT_CONTROL':
            sms_logger.warning("发送短信验证码[失败][触发日发送限额][mobile:%s]" % mobile)
            return gen_response('您今天获取的短信验证码已达最大限额', status=1, response_status=400)
        elif result_code == 'isv.BUSINESS_LIMIT_CONTROL':
            sms_logger.warning("发送短信验证码[失败][触发日发送限额][mobile:%s]" % mobile)
            return gen_response('您今天获取的短信验证码已达最大限额', status=1, response_status=400)
        else:
            sms_logger.warning("发送短信验证码[失败][触发日发送限额][mobile:%s]" % mobile)
            return gen_response('您今天获取的短信验证码已达最大限额', status=1, response_status=400)

然后是serializer的代码
class ImageCodeCheckSerializer(serializers.Serializer):

"""
图片验证码校验序列化器
"""
image_code_id = serializers.UUIDField()
text = serializers.CharField(max_length=4, min_length=4)
mobile = serializers.CharField(max_length=11, min_length=11)

def validate(self, attrs):
    # 从attrs字典里获取相应的数据
    image_code_id = attrs['image_code_id']
    text = attrs['text']
    mobile = attrs['mobile']
    # 判断手机号
    if not re.match(r'^1[3-9]\d{9}$', mobile):
        # return gen_response('手机号格式错误', status=1)
        raise serializers.ValidationError(detail={'status': 1, 'message': '手机号格式错误', 'data': None})

    # 查询真实图片验证码
    redis_conn = get_redis_connection('verify_codes')
    real_text_image_code = redis_conn.get('img_{}'.format(image_code_id))

    if not real_text_image_code:
        # return gen_response('图片验证码无效', status=1)
        raise serializers.ValidationError(detail={'status': 1, 'message': '图片验证码无效', 'data': None})

    # 删除图片验证码
    try:
        redis_conn.delete('img_%s' % image_code_id)
    except RedisError as e:
        logger.error(e)

    # 对比校验
    real_text_image_code = real_text_image_code.decode()
    if real_text_image_code.lower() != text.lower():
        # return gen_response('图片验证码无效', status=1)
        raise serializers.ValidationError(detail={'status': 1, 'message': '图片验证码无效', 'data': None})
    # 判断是否在60s内发送过
    send_flag = redis_conn.get('send_flag_%s' % mobile)
    # 如果send_flag 有值.那么说明已经发送过.那就抛出错误
    if send_flag:
        # return gen_response('请求过于频繁', status=1)
        raise serializers.ValidationError(detail={"status": 1, "message": "请求过于频繁", "data": None})
    return attrs

我是想让raise serializers.ValidationError返回的是我自己定义的这种形式的json
{

"status": 1,
"message": "图片验证码无效",
"data": null

}
但是我请求返回的却是这样的
{

"status": [
    "1"
],
"message": [
    "图片验证码无效"
],
"data": [
    "None"
]

}
每个键对应的值变成了列表。
想问下怎么才能返回自定义的json

阅读 3.4k
2 个回答
新手上路,请多包涵

需要重写Field

在restframework.fields.py中224有一段转换错误提示的函数。

def get_error_detail(exc_info):
    """
    Given a Django ValidationError, return a list of ErrorDetail,
    with the `code` populated.
    """
    code = getattr(exc_info, 'code', None) or 'invalid'

    try:
        error_dict = exc_info.error_dict
    except AttributeError:
        return [
            ErrorDetail((error.message % error.params) if error.params else error.message,
                        code=error.code if error.code else code)
            for error in exc_info.error_list]
    # 这块就是ValidationError传递的错误提示
    return {
        k: [
            ErrorDetail((error.message % error.params) if error.params else error.message,
                        code=error.code if error.code else code)
            for error in errors
        ] for k, errors in error_dict.items()
    }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题