【问题标题】:Python-Eve: Use Pre-Request Event Hooks to modify data before inserting to DBPython-Eve:使用预请求事件挂钩在插入数据库之前修改数据
【发布时间】:2015-12-06 14:00:31
【问题描述】:

我通过在我的 eve-API 上执行 POST 请求将新数据添加到我的数据库中。 由于需要从 Python 端添加一些数据,我想我可以使用 pre-request event hook 添加这些数据。

那么有没有办法在将数据插入数据库之前使用预请求挂钩来修改 POST 请求中包含的数据?我已经了解如何实现这样的钩子,但不知道如何在插入数据库之前修改数据。

【问题讨论】:

    标签: python mongodb eve


    【解决方案1】:

    您可能想查看database hooks,特别是insert hooks

    当 POST 请求到达 API 并且新项目即将存储在数据库中时,会触发这些通风口:

    on_insert 用于每个资源端点。

    on_insert_<resource_name> 用于特定资源端点。

    回调函数可以挂钩这些事件,以任意添加新字段或编辑现有字段。

    在下面的代码中:

    def before_insert(resource_name, documents):
        if resource_name == 'myresource':
            for document in documents:
                document['field'] = 'value'
    
    app = Eve()
    app.on_insert += before_insert
    
    app.run()
    

    每次 POST 访问 API 时,都会调用 before_insert 函数。该函数会为每个文档更新field1。由于在将有效负载发送到数据库之前调用了此回调,因此更改将持久保存到数据库中。

    一个有趣的替代方案是:

    def before_insert(resource_name, documents):
        for document in documents:
            document['field'] = 'value'
    
    app = Eve()
    app.on_insert_myresource += before_insert
    
    app.run()
    

    在回调中,我们不再测试端点名称。这是因为我们将回调挂钩到 on_insert_myresoure 事件,因此只有在 myresource 端点上执行 POST 请求时才会调用该函数。更好的关注点分离,代码更简单,也提高了性能,因为回调不会被 all API 插入。旁注,最终您可以将多个回调挂钩到同一事件(因此使用加法运算符+=)。

    【讨论】:

    • 看起来这个钩子是在验证完成后被调用的。那么有没有办法将此与验证结合起来,因为必填字段仍在引发required_field 错误?
    • 如果这些字段是必需的并且它们缺少验证,则会启动并且文档被拒绝。钩子在插入之前和验证之后触发。你不能简单地使这些字段不是必需的吗?或者,您可以自定义验证器以不同方式处理 required 规则,或者更好地添加对不同规则的支持(查看文档中的“自定义验证”)。
    • 数据库挂钩 on_fetch_item 不适用于 WSGI。当我使用python server.py 运行服务器时,钩子可以工作,但是当使用 WSGI 钩子运行应用程序时,它不起作用,并且控制台中没有显示错误。
    【解决方案2】:

    就我而言,如果给定的属性在数据中,我想复制文档。

    我必须使用 pre_POST 事件挂钩来做到这一点。

    def pre_notifications(request):
        data = json.loads(request.get_data())
        if 'payload' in data and 'condition' in data:
            notification = data['payload']
            documents = []
            users = app.data.pymongo().db.users.find()
            for user in users:
                copy_notification = copy(notification)
                copy_notification['user_email'] = user['user_email']
                documents.append(copy_notification)
            request._cached_data = json.dumps(documents).encode('utf-8')
    

    首先,我尝试替换 request.data 但它不起作用。对代码进行一些搜索后,我发现了 _cached_data 属性。然后就可以了。

    【讨论】:

      【解决方案3】:

      只是为了补充@Gustavo 的回答(我不能在他的回答中发表评论)。您可以在不序列化数据的情况下更新request._cached_json 属性。

      用他的例子:

      def pre_notifications(request):
          data = json.loads(request.get_data())
          if 'payload' in data and 'condition' in data:
              notification = data['payload']
              documents = []
              users = app.data.pymongo().db.users.find()
              for user in users:
                  copy_notification = copy(notification)
                  copy_notification['user_email'] = user['user_email']
                  documents.append(copy_notification)
              request._cached_json = documents
      

      【讨论】:

        猜你喜欢
        • 2014-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-09
        • 2019-11-24
        • 1970-01-01
        相关资源
        最近更新 更多