视频

了解详细信息
我很高兴向大家介绍适用于 Python 的 Redis OM,它是一个强大的以开发者为中心的新 Redis 库,可为您提供诸如对象映射和数据验证等功能。
适用于 Python 的 Redis OM 的此预览版使您可以使用声明性模型对数据进行建模,而 SQLAlchemy、Peewee 和 Django ORM 等对象关系映射器 (ORM) 的用户会感到宾至如归。
但还有更多!每个 Redis OM 模型也是一个 Pydantic 模型,因此您可以使用 Pydantic 的强大且可扩展的数据验证功能。此外,Redis OM 模型可在 Python 库需要 Pydantic 模型的任何位置工作。因此,您可以将 Redis OM 模型与 FastAPI 一起使用,以自动验证和为 API 端点生成 API 文档。
我很喜欢的一项功能是 Redis OM 支持流畅查询表达式和辅助索引。适用于 Python 的 Redis OM 还在同一库中支持异步 (asyncio) 和同步编程。而这一系列强大的功能还在不断增加!
继续阅读以了解我是如何构建此库以及有关一些主要功能的幕后细节的。或者,如果您已准备好使用代码,请查看 入门教程。
开发人员通常通过客户端库访问 Redis 以创建 Redis 数据结构(例如哈希),然后针对它们命令。
许多人喜欢这个基于命令的界面,因为它比使用关系数据库编写 SQL 查询简单。但是,你上一次编写 SQL 是什么时候?使用现代 Web 框架的开发人员倾向于使用 ORM,特别是使用声明性模型。
我喜欢 ORM 的一点是,它们消除了许多与你试图解决的问题无关的复杂性。我们创建了 Redis OM,这样你最终就可以对 Redis 有同样的体验。
适用于 Python 的 Redis OM 包括两个基本模型类,你可以使用它们构建你的模型:HashModel 和 JsonModel。
开源 Redis 用户可以使用 HashModel 将数据存储在 Redis 中作为哈希,而安装了 RedisJSON Redis 模块或使用 Redis Enterprise Cloud 或软件 的用户可以使用 JsonModel 本机存储数据JSON 对象。稍后我会详细介绍这些类之间的区别,但现在,我们将使用 HashModel。
查看这个示例 Redis OM 代码,它定义了一个Customer 模型并使用它将数据保存到 Redis
import datetime
from typing import Optional
from pydantic import EmailStr
from redis_om import HashModel
class Customer(HashModel):
first_name: str
last_name: str
email: EmailStr
join_date: datetime.date
age: int
bio: Optional[str]
# First, we create a new `Customer` object:
andrew = Customer(
first_name="Andrew",
last_name="Brookins",
email="andrew.brookins@example.com",
join_date=datetime.date.today(),
age=38,
bio="Python developer, works at Redis, Inc."
)
# The model generates a globally unique primary key automatically
# without needing to talk to Redis.
print(andrew.pk)
# > '01FJM6PH661HCNNRC884H6K30C'
# We can save the model to Redis by calling `save()`:
andrew.save()
# To retrieve this customer with its primary key, we use `Customer.get()`:
assert Customer.get(andrew.pk) == andrew
此简洁的模型定义立即为你提供 `get()` 和 `save()` 等方法。在幕后,这些方法在 Redis 哈希中管理数据。
但 Redis OM 的功能不仅仅于此。它还生成全局唯一且可排序的主键。这一部分非常有用,让我来解释一下它是如何工作的。
Redis OM 会自动为每个模型实例生成一个全局唯一的主键。你可以使用此主键在 Redis 中保存和检索模型数据。
这些主键保证全局唯一,但它们也完全在客户端中生成,不会向 Redis 发送任何请求。它们还可以排序且紧凑。这一切都归功于通用唯一按字母顺序排序标识符 (ULID) 规范。
Redis OM 主键是 ULID,由 python-ulid 提供。你可以在此阅读有关 ULID 规范的更多信息。它非常酷!
除了这些持久性功能之外,你还可以使用 Pydantic 进行数据验证。让我们深入研究验证的工作原理。
Redis 和关系数据库之间的一个区别是,Redis 不会强制执行模式,因此你可以将字符串写入 Redis,然后稍后用数字覆盖它。这比关系数据库更灵活,但也意味着应用程序负责数据验证。
我们认为你不应该想办法在应用程序中处理验证,因此每个 Redis OM 模型也是一个 Pydantic 模型。这意味着你可以根据模型中的类型提示获取基于 Pydantic 的验证,并且可以通过标准 Pydantic 钩子(包括自定义验证器)控制验证。
以下是一些演示验证工作原理的示例代码
import datetime
from typing import Optional
from pydantic import EmailStr, ValidationError
from redis_om import HashModel
class Customer(HashModel):
first_name: str
last_name: str
email: EmailStr
join_date: datetime.date
age: int
bio: Optional[str]
try:
Customer(
first_name="Andrew",
last_name="Brookins",
email="Not an email address!",
join_date=datetime.date.today(),
age=38,
bio="Python developer, works at Redis, Inc."
)
except ValidationError as e:
print(e)
"""
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
email
value is not a valid email address (type=value_error.email)
"""
如果 Python 的 Redis OM 只为你提供了持久性方法和数据验证,那么我认为它非常酷。但我们希望为你处理更多复杂性,为此我们需要帮助你编写富有表现力的查询,就像使用 ORM 一样。接下来,我将讨论这些查询如何工作。
ORM 不仅仅为你提供声明式模型。它们还提供了一个 API,让你可以基于主键以外的属性查询数据。想象一下找到所有超过一定年龄的客户、在特定日期之前注册的客户等等。
开箱即用,Redis 非常适合使用主键查找数据。毕竟,它是一个键值存储,其值是数据结构。但 Redis 不包括查询和二级索引系统,所以如果你想对数据进行索引和查询,你必须自己以复杂的方式管理索引。
在此,我们希望为你处理这种复杂性,因此我们在基本 Redis 模块 RediSearch 的基础上构建了流利的查询表达式。RediSearch 是一个源代码可用的模块,它为你提供了 Redis 中缺少的查询和索引功能。
让我们看看如果将 客户 模型上的几个字段标记为 `index=True` 会发生什么情况。现在,我们可以使用该模型进行查询
import datetime
from typing import Optional
from pydantic import EmailStr
from redis_om import (
Field,
HashModel,
Migrator
)
from redis_om import get_redis_connection
class Customer(HashModel):
first_name: str
last_name: str = Field(index=True)
email: EmailStr
join_date: datetime.date
age: int = Field(index=True)
bio: Optional[str]
# Now, if we use this model with a Redis deployment that has the
# RediSearch module installed, we can run queries like the following.
# Before running queries, we need to run migrations to set up the
# indexes that Redis OM will use. You can also use the `migrate`
# CLI tool for this!
redis = get_redis_connection()
Migrator(redis).run()
# Find all customers with the last name "Brookins"
Customer.find(Customer.last_name == "Brookins").all()
# Find all customers that do NOT have the last name "Brookins"
Customer.find(Customer.last_name != "Brookins").all()
# Find all customers whose last name is "Brookins" OR whose age is
# 100 AND whose last name is "Smith"
Customer.find((Customer.last_name == "Brookins") | (
Customer.age == 100
) & (Customer.last_name == "Smith")).all()
此表达式语法可能看上去很熟悉,它融合了我喜欢 Peewee、SQLAlchemy 和 Django ORM 的一切内容。
使用 Redis 对复杂数据进行建模时,你不可避免地想要存储嵌入式数据。如果你使用 Redis 哈希对客户数据进行建模,则可能想在各个客户的哈希中存储诸如客户收货地址之类的信息。遗憾的是,Redis 哈希无法存储诸如 List、Set 或其他哈希之类的嵌套容器,因此这样做行不通。
在这种情况中,将数据存储为原生 JSON 对象将变得很有意义。如果你以 JSON 文档的形式对客户数据进行建模,则可以在单个客户记录中内嵌任何想要的内容。
但是,Redis 本身不支持 JSON。正是出于这个原因,我们创建了可供公开访问的 RedisJSON 模块。借助 RedisJSON,可将 Redis 用作文档数据库,轻松存储和查询复杂的 JSON 对象。
在 Python 版 Redis OM 中,如果 Redis 实例已安装 RedisJSON,则可以使用 JsonModel 类。通过此模型类可在其他 JsonModels 中嵌入 JsonModels。设想客户拥有一个订单数组,每个订单都有一个数组,依此类推。
下面是使用 Python 版 Redis OM 嵌入的 JSON 模型的外观
import datetime
from typing import Optional
from redis_om import (
EmbeddedJsonModel,
JsonModel,
Field,
Migrator,
)
from redis_om import get_redis_connection
class Address(EmbeddedJsonModel):
address_line_1: str
address_line_2: Optional[str]
city: str = Field(index=True)
state: str = Field(index=True)
country: str
postal_code: str = Field(index=True)
class Customer(JsonModel):
first_name: str = Field(index=True)
last_name: str = Field(index=True)
email: str = Field(index=True)
join_date: datetime.date
age: int = Field(index=True)
bio: Optional[str] = Field(index=True, full_text_search=True,
default="")
# Creates an embedded model.
address: Address
# With these two models and a Redis deployment with the RedisJSON
# and RediSearch modules installed, we can run queries like the
# following.
# Before running queries, we need to run migrations to set up the
# indexes that Redis OM will use. You can also use the `migrate`
# CLI tool for this!
redis = get_redis_connection()
Migrator(redis).run()
# Find all customers who live in San Antonio, TX
Customer.find(Customer.address.city == "San Antonio",
Customer.address.state == "TX")
你不仅获得了存储复杂 JSON 对象的灵活性,而且 Python 版 Redis OM 意识到这些嵌套结构,可针对这些结构编写查询表达式。太棒了!
我希望你能看出我对 Python 版 Redis OM 有多么兴奋。我已致力于将当前 Python 生态系统中的部分最佳元素整合在一起,以便为 Redis 开发人员处理复杂问题,而按照我的看法,没有其他人需要对此进行处理。
如果你已对此产生兴趣,请查看 入门教程。Python 版 Redis OM 正处于非常早期的阶段,我们称其为“预览”。因此存在粗略环节,你将遇到错误,我们仍在努力提供完整说明。但是愿景摆在那里,且我鼓励你看看。
最后,我要说,我们从声明性数据模型开始,但我们还有更多内容要构建,既包括数据建模方面的,也包括更广泛的。敬请期待更令人兴奋的 Redis OM 功能!