Skip to main content

用于 Python 的 Redis 对象映射器

项目描述

https://travis-ci.org/josiahcarlson/rom.svg?branch=master

Rom - Python 的 Redis 对象映射器

版权所有 2013-2021 乔赛亚·卡尔森

在 LGPL 许可证版本 2.1 和版本 3 下发布(您可以选择要绑定的版本)。

提供赞助

不喜欢 LGPL?赞助该项目并获得几乎任何您想要的许可证。

该项目部分由 structd.com 赞助。从历史上看,rom 已被用于帮助支持 chownow.com 的数百万份食品订单的交付,并已被用作几家初创公司的主要后端和原型,这些初创公司一路走到了 A 系列。

感谢我们的赞助商和那些使用我们服务的人。

欢迎您提供良好的服务。

您的公司链接在这里。

文档

可以找到更新的文档:https ://josiahcarlson.github.io/rom/

什么

Rom 是一个包,其目的是在 Python 的 Redis 中提供活动记录样式的数据建模,类似于 Django ORM、SQLAlchemy、Google 的 Appengine 数据存储等的语义。

为什么

我正在构建一个个人项目,想使用 Redis 来存储我的一些数据,但不想糟糕地破解它。我查看了 Python 中可用的现有 Redis 对象映射器,但不喜欢提供的特性和功能。

有什么可用的

数据类型:

  • 字符串(2.x:str/unicode,3.3+:str)、整数、浮点数、小数、布尔值

  • 日期时间.日期时间,日期时间.日期,日期时间.时间

  • Json 列(用于嵌套结构)

  • OneToMany 和 ManyToOne 列(用于模型参考)

  • 非rom ForeignModel 参考支持

索引:

  • 数值范围获取、搜索和排序

  • 全字文本搜索(查找带有 col X 的单词 A 和 B 的条目)

  • 前缀匹配(可用于基于前缀的自动完成)

  • 后缀匹配(可用于基于后缀的自动完成)

  • 基于字符串的列的模式匹配

  • 使用 Redis 2.6.0 及更高版本时,除地理索引之外的所有索引均可用

  • Redis 3.2.0 及更高版本提供地理索引

其它功能:

  • 每线程实体缓存(尽量减少往返,轻松保存所有实体)

  • 缓存查询结果并获取任何其他用途的密钥的能力(请参阅: Query.cached_result()

入门

  1. 确保已安装 Python 2.6、2.7 或 3.3+

  2. 确保您安装了 Andy McCurdy 的 Redis 客户端库: https ://github.com/andymccurdy/redis-py/或 https://pypi.python.org/pypi/redis

  3. 确保您已安装 Python 2 和 3 兼容库“六”:https ://pypi.python.org/pypi/six

  4. (可选)确保为 Python 安装了hiredis 库

  5. 确保您已安装 Redis 服务器并可远程使用

  6. 通过 rom.util.set_connection_settings()更新rom的 Redis 连接设置(其他连接更新选项,包括每个模型的连接,可以在rom.util 文档中阅读):

    import redis
    from rom import util
    
    util.set_connection_settings(host='myhost', db=7)
  1. 创建模型:

    import rom
    
    # All models to be handled by rom must derived from rom.Model
    class User(rom.Model):
        email = rom.String(required=True, unique=True, suffix=True)
        salt = rom.String()
        hash = rom.String()
        created_at = rom.Float(default=time.time)
  2. 创建模型实例并保存:

    PASSES = 32768
    def gen_hash(password, salt=None):
        salt = salt or os.urandom(16)
        comp = salt + password
        out = sha256(comp).digest()
        for i in xrange(PASSES-1):
            out = sha256(out + comp).digest()
        return salt, out
    
    user = User(email='user@host.com')
    user.salt, user.hash = gen_hash(password)
    user.save()
    # session.commit() or session.flush() works too
  3. 稍后加载并使用该对象:

    user = User.get_by(email='user@host.com')
    at_gmail = User.query.endswith(email='@gmail.com').all()

Lua 支持

从 0.25.0 及更高版本开始,rom 假定您使用的是 Redis 2.6 或更高版本,它支持服务器端 Lua 脚本。这允许支持多个唯一列约束,而无需烦人的竞争条件和重试。这也允许在某些列类型上支持前缀、后缀和模式匹配。

如果您使用的是 2.6 之前的 Redis 版本,则应升级 Redis。如果您无法或不愿意升级 Redis,但仍希望使用 rom,则应调用rom._disable_lua_writes(),这将阻止您使用需要 Lua 脚本支持的功能。

即将到期的模型/TTL

有一系列功能请求/错误报告/拉取请求以添加 rom 自动删除和/或过期存储在 Redis 中的实体数据的能力。这是一个已提出(截至 2016 年 1 月)6 次不同的请求。

长话短说:rom 将一堆数据存储在二级结构中以加快查询速度。当模型“过期”时,该数据不会被删除。要删除该数据,您必须运行一个清理功能,该功能必须扫描每个实体以确定模型是否已过期。这是一个巨大的浪费,是好的设计的对立面。

相反,如果您使用index=True创建一个新的expire_at浮点列,则该列可以存储实体何时到期。然后要使数据过期,您可以使用:Model.query.filter(expire_at=(0, time.time())).limit(10)来(例如)获取最多 10 个需要过期的最旧实体.

现在,我知道你在想什么。你在想,“但我希望数据会自行消失。” 我不反对。但要做到这一点,Redis 需要增加 Lua 脚本触发器,或者您需要运行一个单独的守护进程来定期清理剩余数据。但是……如果你需要运行一个单独的守护进程来通过扫描你所有的 rom 实体来清理剩余的数据,那么保持一个明确的列并有效地完成它不是更好/更快吗?我想是的,你也应该如此。