您如何使用 Pyramid 的 Colander 验证应用程序逻辑?

How do you validate application logic using Pyramid's Colander?

到目前为止,我正在使用漏勺验证我的 aiohttp 应用程序中的数据。

我面临的问题是我不知道如何进行"deep"验证。

给定以下架构:

import colander

class User(colander.MappingSchema):
    username = colander.SchemaNode(colander.String())
    password = colander.SchemaNode(colander.String())
    confirmation = colander.SchemaNode(colander.String())

我都验证了输入数据结构是否包含所有必填字段(为清楚起见,限制最少)但我还需要 检查:

所以在我的控制器中,代码看起来像下面的伪代码:

def create_user(request):
    user = await request.json()
    schema = User()
    # do schema validation
    try:
        user = schema.deserialize(user)
    except colander.Invalid, exc:
        response = dict(
            status='error',
            errors=errors.asdict()
        )
        return json_response(response)
    else:
        # check password and confirmation are the same
        if user['password'] != user['confirmation']:
            response = dict(
                status='error'
                errors=dict(confirmation="doesn't match password")
            )
            return json_response(response)
        # check the user is not already used by another user
        # we want usernames to be unique
        if user_exists(user['user']):
            response = dict(
                status='error',
                errors=dict(username='Choose another username')
            )
            return json_response(response)

        return json_response(dict(status='ok'))

基本上有两种验证。是否可以在单个漏勺模式中同时拥有这两种逻辑?这是一个好的模式吗?

显然这是个人喜好问题,但恕我直言,最好将数据验证与应用程序逻辑分开。

您还会 运行 遇到一些试图确认用户名唯一的问题:

  1. Colander 需要了解您的应用程序,例如。访问数据库连接以检查该用户名不存在的数据库。
  2. Colander (AFAIK) 没有为 asyncio 编程设置,因此在处理检查用户是否存在的 async 方法时会遇到问题。
  3. 您确实希望用户创建是 ACID,因此使用相同用户名同时调用 create_user 不可能创建两个具有相同用户名的用户。

检查密码匹配是另一回事,不需要任何关于世界其他地方的知识,使用漏勺应该相当简单。我不是漏勺专家,但看起来您可以使用 deferred validator 来检查两个密码是否匹配。

关于您的代码的一些其他说明:

  1. create_user 应该是 async 方法
  2. 我对你的数据库一无所知,但要从异步编程中获得任何优势 user_exists 也应该是异步的
  3. 用户存在性检查应包装到 ACID 用户创建中。例如。您应该使用 postgres 的 on conflict 或等价物来在创建用户时捕获重复用户,而不是先检查它们是否存在
  4. 为了正确 restful 并使测试更容易,您的视图应该 return 错误时的正确 http 响应代码(目前您 return 200 用于所有状态)。您应该使用 201 表示已创建,400 表示无效日期,409 或用户名冲突。