当前位置: 首页 > 工具软件 > flask-restx > 使用案例 >

Flask 学习-45.Flask-RESTX 自定义参数校验和自定义错误内容 error_msg 使用

汤跃
2023-12-01

前言

在校验请求参数的时候,除了一些基本的required=True, type类型外,还会遇到一些校验,比如是否为空,字符串长度,以及一些自定义的参数规则。

add_argument 参数

class Argument(object):
    """
    :param name: Either a name or a list of option strings, e.g. foo or -f, --foo.
    :param default: The value produced if the argument is absent from the request.
    :param dest: The name of the attribute to be added to the object
        returned by :meth:`~reqparse.RequestParser.parse_args()`.
    :param bool required: Whether or not the argument may be omitted (optionals only).
    :param string action: The basic type of action to be taken when this argument
        is encountered in the request. Valid options are "store" and "append".
    :param bool ignore: Whether to ignore cases where the argument fails type conversion
    :param type: The type to which the request argument should be converted.
        If a type raises an exception, the message in the error will be returned in the response.
        Defaults to :class:`unicode` in python2 and :class:`str` in python3.
    :param location: The attributes of the :class:`flask.Request` object
        to source the arguments from (ex: headers, args, etc.), can be an
        iterator. The last item listed takes precedence in the result set.
    :param choices: A container of the allowable values for the argument.
    :param help: A brief description of the argument, returned in the
        response when the argument is invalid. May optionally contain
        an "{error_msg}" interpolation token, which will be replaced with
        the text of the error raised by the type converter.
    :param bool case_sensitive: Whether argument values in the request are
        case sensitive or not (this will convert all values to lowercase)
    :param bool store_missing: Whether the arguments default value should
        be stored if the argument is missing from the request.
    :param bool trim: If enabled, trims whitespace around the argument.
    :param bool nullable: If enabled, allows null value in argument.
    """

    def __init__(
        self,
        name,
        default=None,
        dest=None,
        required=False,
        ignore=False,
        type=text_type,
        location=("json", "values",),
        choices=(),
        action="store",
        help=None,
        operators=("=",),
        case_sensitive=True,
        store_missing=True,
        trim=False,
        nullable=True,
    ):
        self.name = name
        self.default = default
        self.dest = dest
        self.required = required
        self.ignore = ignore
        self.location = location
        self.type = type
        self.choices = choices
        self.action = action
        self.help = help
        self.case_sensitive = case_sensitive
        self.operators = operators
        self.store_missing = store_missing
        self.trim = trim
        self.nullable = nullable

nullable=False 不允许为None

required=True 设置该参数是必传项, nullable=False 是设置该参数不允许为None

class Register(Resource):

    def post(self):
        # 校验入参
        parser = reqparse.RequestParser()
        parser.add_argument('username', required=True, type=str,  nullable=False, help='username is required')
        parser.add_argument('password', required=True, type=str,  nullable=False, help='password is required')
        args = parser.parse_args()

        # # 获取入参
        # data = request.get_json()
        print(f'请求入参:{args}')
        return jsonify({
            "code": 0,
            "msg": "success"
        })


# 注册
api.add_resource(Register, '/api/v1/register')

需注意的是这里是不能为null, 传空字符串还是可以的。

default=''设置默认值

对address 参数设置默认值,当用户没传address 参数的时候,就会取默认值

   def post(self):
        # 校验入参
        parser = reqparse.RequestParser()
        parser.add_argument('username', required=True, type=str,  nullable=False, help='username is required')
        parser.add_argument('password', required=True, type=str,  nullable=False, help='password is required')
        parser.add_argument('address', default='上海市',  type=str, help='address invalid')
        args = parser.parse_args()
        print(f'请求入参:{args}')

请求示例

POST http://127.0.0.1:5000/api/v1/register HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:5000
Content-Type: application/json
Content-Length: 56

{
    "username": "test",
    "password" : "111111"
}

args 得到的参数

{'username': 'test', 'password': '111111', 'address': '上海市'}

choices 设置参数可选值

比如性别设置可选项:男、女

    def post(self):
        # 校验入参
        parser = reqparse.RequestParser()
        parser.add_argument('username', required=True, type=str,  nullable=False, help='username is required')
        parser.add_argument('password', required=True, type=str,  nullable=False, help='password is required')
        parser.add_argument('sex', choices=["男", "女"],  type=str, help='sex invalid')
        args = parser.parse_args()

        print(f'请求入参:{args}')

请求示例,sex不是可选项的时候会报400

POST http://127.0.0.1:5000/api/v1/register HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:5000
Content-Type: application/json
Content-Length: 73

{
    "username": "test",
    "password" : "111111",
    "sex": "x"
}


HTTP/1.0 400 BAD REQUEST
Content-Type: application/json
Content-Length: 152
Server: Werkzeug/2.0.1 Python/3.8.5
Date: Sun, 04 Sep 2022 12:26:41 GMT

{
    "errors": {
        "sex": "sex invalid The value 'x' is not a valid choice for 'sex'."
    },
    "message": "Input payload validation failed"
}

设置字符串长度

比如限制 password 是 6-16 位,由于 add_argument 没提供对应的方法,需我们自定义参数校验类型

class Register(Resource):

    @staticmethod
    def password_validate(value, name):
        if len(value) < 6 or len(value) > 16:
            raise ValueError(name + '参数长度不合法')
        return value

    def post(self):
        # 校验入参
        parser = reqparse.RequestParser()
        parser.add_argument('username', required=True, type=str,  nullable=False, help='username invalid')
        parser.add_argument('password', required=True, type=self.password_validate,  
                            nullable=False, help='password invalid must 6-16')
        # parser.add_argument('sex', choices=["男", "女"],  type=str, help='sex invalid')
        args = parser.parse_args()

        print(f'请求入参:{args}')

如果密码长度小于6位,会返回400

POST http://127.0.0.1:5000/api/v1/register HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:5000
Content-Type: application/json
Content-Length: 55

{
    "username": "test",
    "password" : "12345"
}

HTTP/1.0 400 BAD REQUEST
Content-Type: application/json
Content-Length: 176
Server: Werkzeug/2.0.1 Python/3.8.5
Date: Sun, 04 Sep 2022 12:32:25 GMT

{
    "errors": {
        "password": "password invalid must 6-16 password参数长度不合法"
    },
    "message": "Input payload validation failed"
}

错误信息error_msg

每个字段的错误消息可以使用help参数 to Argument(以及RequestParser.add_argument)进行自定义。
如果未提供help 参数,则该字段的错误消息将是类型错误本身的字符串表示形式。如果help提供,则错误消息将是 的值help。
help可能包含一个插值标记 ,{error_msg}它将被替换为类型错误的字符串表示形式。这允许在保留原始错误的同时自定义消息:

from flask_restx import reqparse


parser = reqparse.RequestParser()
parser.add_argument(
    'foo',
    choices=('one', 'two'),
    help='Bad choice: {error_msg}'
)

# If a request comes in with a value of "three" for `foo`:

{
    "message":  {
        "foo": "Bad choice: three is not a valid choice",
    }
}

bundle_errors 错误处理

RequestParser 处理错误的默认方式是在发生第一个错误时中止。当您有可能需要一些时间来处理的论点时,这可能会很有用。
但是,通常最好将错误捆绑在一起并一次性发送回客户端。可以在 Flask 应用程序级别或特定的 RequestParser 实例上指定此行为。
要使用捆绑错误选项调用 RequestParser,请传入参数bundle_errors。例如

from flask_restx import reqparse

parser = reqparse.RequestParser(bundle_errors=True)
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True)

# If a request comes in not containing both 'foo' and 'bar', the error that
# will come back will look something like this.

{
    "message":  {
        "foo": "foo error message",
        "bar": "bar error message"
    }
}

# The default behavior would only return the first error

parser = RequestParser()
parser.add_argument('foo', type=int, required=True)
parser.add_argument('bar', type=int, required=True)

{
    "message":  {
        "foo": "foo error message"
    }
}

BUNDLE_ERRORS 可以作为全局配置参数,例如

from flask import Flask

app = Flask(__name__)
app.config['BUNDLE_ERRORS'] = True

警告:
BUNDLE_ERRORS是覆盖bundle_errors 单个RequestParser实例中的选项的全局设置。

inputs 匹配入参

flask_restful.inputs 常用的一些数据校验

  • url:会判断这个参数的值是否是一个url,如果不是,那么就会抛出异常。
  • regex:正则表达式。
  • date:将这个字符串转换为datetime.date数据类型。如果转换不成功,则会抛出一个异常。

写一个注册视图,对请求入参校验

class RegisterView(Resource):

    def post(self):
        # 创建解析器对象
        parser = reqparse.RequestParser()
        # 需要验证的参数
        parser.add_argument('username', type=str, required=True, trim=True, help='用户名不合法' )
        parser.add_argument('password', type=str, required=True, help='密码不合法')
        parser.add_argument('age', type=int, help='年龄不合法')
        parser.add_argument('sex', type=str, choices=['男', '女'], help='性别不合法')
        parser.add_argument('birthday', type=inputs.date, help='生日类型不合法')
        parser.add_argument('phone', type=inputs.regex(r'1[3578]\d{9}'), help='手机号不合法')
        parser.add_argument('url', type=inputs.url, help='url不合法')
        args = parser.parse_args()
        print(f'请求入参:{args}')

        return {"code": 0}

请求参数示例

{
    "username": "test",
    "password" : "12345",
    "age": 22,
    "sex": "男",
   "birthday": "2021-01-09",
   "phone": "134444322222",
    "url": "https://www.cnblogs.com/yoyoketang/"
}

add_argument方法可以指定这个字段的名字,这个字段的数据类型等,验证错误提示信息等。

  • default:默认值,如果这个参数没有值,那么将使用这个参数指定的默认值。
  • required:是否必须。默认为False,如果设置为True,那么这个参数就必须提交上来。
  • type:这个参数的数据类型,如果指定,那么将使用指定的数据类型来强制转换提交上来的值。
  • choices:固定选项。提交上来的值只有满足这个选项中的值才符合验证通过,否则验证不通过。
  • help:错误信息。如果验证失败后,将会使用这个参数指定的值作为错误信息。
  • trim:是否要去掉前后的空格。
  • type: 可以使用python自带的一些数据类型(如str或者int),也可以自定义类型
 类似资料: