非阻塞 PostgreSQL ORM

Nonblocking PostgreSQL ORM

我有一个使用 Scrapy 的网络抓取工具,它是在使用 Deferreds 的 Twisted 上构建的。对于抓取的每个页面,我想插入到 PostgreSQL 数据库中的几个不同表中。我希望这个插入是非阻塞的。有没有办法让 Postgres 与像 SQLAlchemy 这样的 ORM 进行非阻塞交互?

我知道 Postgres 可以与 alchimiatxpostgres 进行非阻塞交互,但两者均不提供 ORM 功能。如果答案是不可能的,我会使用其中之一。其中一个比另一个更受欢迎吗?

在 Python 中构建 ORM 的方式通常不适用于异步操作。

Python ORM 的一个主要特征似乎很吸引人,显然是获取和设置值的正常属性访问。但是,这两个都存在问题。

对于异步操作的属性访问,显而易见的行为是将 database_object.some_field 之类的值计算为 Deferred。然后应用程序将等待它接收实际值。代码最终看起来像这样:

d = database_object.some_field
def got_some_field(result):
    print("DB obj some_field = {}".format(result))
d.addCallback(got_some_field)

您得到的不是简单的表达式,而是四行代码。有人可能会争辩说,这完全破坏了 ORM 旨在提供的价值。通过从数据库预加载值,可能 可以解决此问题。然而,预加载所有内容并不总是可取的(它会损害性能)并且这样做并不总是很明显是正确的(如果你开始一个事务,预加载一些值,执行一个可能改变这些值的操作,然后从 Python 对象中检索它们,应该发生什么?)。

更新值更糟糕。而同步 ORM 可能会让您:

database_object.some_field = 3

异步 ORM 如何处理类似的东西?赋值根本不能产生值。所以你需要另一个不方便的模式才能正确地进行更新。类似于:

d = database_object.update("some_field", 3)
def updated(ignored):
    # Continue ...
d.addCallback(updated)

或者一个非常复杂的系统在幕后以不允许数据库中的值与 Python 中内存中的值之间的不一致的方式执行此操作。这可能并非不可能,但所涉及的复杂程度可能是为什么似乎没有人解决这个问题的原因。

名为“postgresql-orm”的包具有默认连接器 class 和 连接池 并且每个请求使用池中的第一个空闲连接:

# pip install postgresql-orm
# pip install psycopg2-binary

import sql

import logging as log
log.basicConfig(level=log.DEBUG) # To see executed queries


sql.db = sql.Db('dbname=postgres user=postgres password=1234 host=127.0.0.1 port=5432', 
                size=20) # It will work with separate 20 connections in this case


class ParsedItem:
    pass

class Table(sql.Table):
    type = ParsedItem
    name = 'parsed_item'
    fields = {
        'id': {'type': 'int'},
        'some_field_1': {}
        'some_field_2': {}
    }

Table.add({
    'some_field_1': 'Some value 1',
    'some_field_2': 'Some value 2',
})

文档在这里:https://pypi.org/project/postgresql-orm/