Skip to content

模型和字段

Redis OM 对象映射、验证和查询功能的核心是一对声明性模型:HashModelJsonModel。这两个模型提供大致相同的 API,但它们在 Redis 中存储数据的方式不同。

本页将解释如何通过子类化这些类之一来创建您的 Redis OM 模型。

HashModel 与 JsonModel

首先,您应该使用哪个?

选择相对简单。如果您想将一个模型嵌入到另一个模型中,比如将一个 Customer 模型与一个 Order 模型列表关联,那么您需要使用 JsonModel。只有 JsonModel 支持嵌入模型。

否则,使用 HashModel

创建您的模型

您可以通过子类化 HashModelJsonModel 来创建 Redis OM 模型。例如:

from redis_om import HashModel


class Customer(HashModel):
    first_name: str
    last_name: str

配置模型

您可以在模型中配置多个特定于 Redis OM 的设置。您可以使用一个称为 Meta 对象 的特殊对象来配置这些设置。

以下是使用 Meta 对象设置全局键前缀的示例:

from redis_om import HashModel


class Customer(HashModel):
    first_name: str
    last_name: str

    class Meta:
        global_key_prefix = "customer-dashboard"

抽象模型

您可以通过在 HashModelJsonModel 之上子类化 ABC 来创建抽象 Redis OM 模型。抽象模型仅存在于为子类收集共享配置的目的——您无法实例化它们。

抽象模型的一个用途是配置应用程序中所有模型都将使用的 Redis 键前缀。这是与 Redis 的一个良好最佳实践。以下是使用抽象模型的方法:

from abc import ABC

from redis_om import HashModel


class BaseModel(HashModel, ABC):
    class Meta:
        global_key_prefix = "your-application"

Meta 对象是“特殊的”

Meta 对象有一个特殊的属性:如果您从具有 Meta 对象的基类创建模型子类,Redis OM 会将父类的字段复制到子类的 Meta 对象中。

因此,子类可以在其父类的 Meta 类中重写单个字段,而无需重新定义所有字段。

一个示例将使这一点更加清晰:

from abc import ABC

from redis_om import HashModel, get_redis_connection


redis = get_redis_connection(port=6380)
other_redis = get_redis_connection(port=6381)


class BaseModel(HashModel, ABC):
    class Meta:
        global_key_prefix = "customer-dashboard"
        database = redis


class Customer(BaseModel):
    first_name: str
    last_name: str

    class Meta:
        database = other_redis


print(Customer.global_key_prefix)
# > "customer-dashboard"

在这个例子中,我们创建了一个名为 BaseModel 的抽象基模型,并为其提供了一个包含数据库连接和全局键前缀的 Meta 对象。

然后我们创建了一个名为 CustomerBaseModel 子类,并为其提供了第二个 Meta 对象,但只定义了 databaseCustomer 也获得了 BaseModel 定义的全局键前缀("customer-dashboard")。

虽然这与 Python 中通常的对象继承方式不同,但我们认为这有助于使抽象模型更有用,尤其是作为分组共享模型设置的一种方式。

Meta 对象支持的所有设置

以下是 Meta 对象中可用设置及其控制内容的表格。

设置 描述 默认值
global_key_prefix 应用于模型管理的每个 Redis 键的字符串前缀。这可以是您应用程序的名称。 ""
model_key_prefix 应用于表示每个模型的 Redis 键的字符串前缀。例如,HashModel 的 Redis Hash 键。此前缀也会添加到为每个具有索引字段的模型创建的 redisearch 索引中。 f"{new_class.module}.{new_class.name}"
primary_key_pattern 生成表示此模型的 Redis 键的基础字符串的格式字符串。此字符串应接受一个 "pk" 格式参数。注意:这是一个“新风格”的格式字符串,将通过 .format() 调用。 "{pk}"
database 模型将用于与 Redis 通信的 redis.asyncio.Redis 或 redis.Redis 客户端实例。 使用 connections.get_redis_connection() 创建的新实例。
primary_key_creator_cls 遵循 PrimaryKeyCreator 协议的类,Redis OM 将使用该类为新的模型实例创建主键。 UlidPrimaryKey
index_name 此模型使用的 RediSearch 索引名称。仅在至少一个模型的字段被标记为可索引(index=True)时使用。 "{global_key_prefix}:{model_key_prefix}:index"
embedded 此模型是否为“嵌入式”。嵌入式模型不包括在创建和销毁索引的迁移中。相反,它们的索引字段包含在父模型的索引中。注意:只有 JsonModel 可以拥有嵌入式模型。 False
encoding 用于字符串的默认编码。此编码在连接级别传递给 redis-py。在这两种情况下,Redis OM 将使用您选择的编码解码来自 Redis 的二进制字符串。 "utf-8"

配置 Pydantic

每个 Redis OM 模型也是一个 Pydantic 模型,因此除了使用 Meta 对象配置 Redis OM 行为外,您还可以通过模型类中的 Config 对象控制 Pydantic 配置。

有关此对象的工作方式和可用设置的详细信息,请参阅 Pydantic 文档

Redis OM 为模型设置的默认 Pydantic 配置相当于以下内容(在实际模型上演示):

from redis_om import HashModel


class Customer(HashModel):
    # ... 字段 ...

    model_config = ConfigDict(
        from_attributes=True,
        arbitrary_types_allowed=True,
        extra="allow",
    )

如果您更改这些设置,某些功能可能无法正常工作。

字段

您可以使用 Python 类型注解 在 Redis OM 模型上定义字段。如果您对类型注解不熟悉,可以查看这个 教程

这与 Pydantic 的工作方式完全相同。有关字段类型的指导,请查看 Pydantic 文档

使用 HashModel

HashModel 将数据存储在 Redis Hash 中,结构是扁平的。这意味着 Redis Hash 不能包含 Redis Set、List 或 Hash。由于这个要求,HashModel 当前也不支持容器类型,例如:

  • 集合
  • 列表
  • 字典和其他“映射”类型
  • 其他 Redis OM 模型
  • Pydantic 模型

注意:将来,我们可能会将这些值序列化为 JSON 字符串,就像我们对 JsonModel 所做的那样。不同之处在于,在 HashModel 的情况下,您将无法对这些字段进行索引,只能获取和保存它们。而在 JsonModel 中,您可以对列表字段和嵌入的 JsonModel 进行索引。

因此,简而言之,如果您想使用容器类型,请使用 JsonModel

使用 JsonModel

好消息!JsonModel 支持容器类型。

我们将使用 Pydantic 的 JSON 序列化和编码来序列化您的 JsonModel 并将其保存在 Redis 中。

默认值

字段可以具有默认值。您通过为字段赋值来设置它们。

import datetime
from typing import Optional

from redis_om import HashModel


class Customer(HashModel):
    first_name: str
    last_name: str
    email: str
    join_date: datetime.date
    age: int
    bio: Optional[str] = "Super dope"  # <- 在这里添加了默认值

现在,如果我们创建一个没有 bio 字段的 Customer 对象,它将使用默认值。

import datetime
from typing import Optional

from redis_om import HashModel


class Customer(HashModel):
    first_name: str
    last_name: str
    email: str
    join_date: datetime.date
    age: int
    bio: Optional[str] = "Super dope"


andrew = Customer(
    first_name="Andrew",
    last_name="Brookins",
    email="andrew.brookins@example.com",
    join_date=datetime.date.today(),
    age=38)  # <- 注意,我们没有提供 bio!

print(andrew.bio)  # <- 所以我们得到了默认值。
# > 'Super Dope'

模型将在您下次调用 save() 时将此默认值保存到 Redis。

标记字段为索引

如果您在 Redis 实例中使用 RediSearch 模块,可以将字段标记为“索引”。一旦您将模型中的任何字段标记为索引,Redis OM 会自动为该模型创建和管理一个二级索引,使您能够对任何索引字段进行查询。

要将字段标记为索引,您需要使用 Redis OM 的 Field() 助手,如下所示:

from redis_om import (
    Field,
    HashModel,
)


class Customer(HashModel):
    first_name: str
    last_name: str = Field(index=True)

在这个例子中,我们将 Customer.last_name 标记为索引。

要为具有索引字段的任何模型创建索引,请使用 Redis OM 安装在您的 Python 环境中的 migrate CLI 命令。

该命令会检测您项目中的任何 JsonModelHashModel 实例,并对每个不是抽象或嵌入的模型执行以下操作:

  • 如果模型尚未存在索引:
  • 迁移工具创建一个索引
  • 迁移工具存储索引定义的哈希
  • 如果模型存在索引:
  • 迁移工具检查存储的索引哈希是否过时
  • 如果存储的哈希过时,迁移工具会删除索引(不会删除您的数据!)并使用新的索引定义重建它

您也可以通过代码自行运行 Migrator

from redis_om import (
    get_redis_connection,
    Migrator
)

redis = get_redis_connection()
Migrator().run()