%global _empty_manifest_terminate_build 0 Name: python-redis-om Version: 0.1.2 Release: 1 Summary: Object mappings, and more, for Redis. License: BSD-3-Clause URL: https://github.com/redis/redis-om-python Source0: https://mirrors.nju.edu.cn/pypi/web/packages/d8/ac/51b504acb91f66997b1d8c0a3f37f8a4a7c3e33ed93bd4cba59bab2ff660/redis_om-0.1.2.tar.gz BuildArch: noarch Requires: python3-redis Requires: python3-pydantic Requires: python3-click Requires: python3-pptree Requires: python3-types-redis Requires: python3-ulid Requires: python3-typing-extensions Requires: python3-hiredis Requires: python3-more-itertools %description [![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Build Status][ci-svg]][ci-url] **Redis OM Python** makes it easy to model Redis data in your Python applications. [Redis OM .NET](https://github.com/redis/redis-om-dotnet) | [Redis OM Node.js](https://github.com/redis/redis-om-node) | [Redis OM Spring](https://github.com/redis/redis-om-spring) | **Redis OM Python**
Table of contents span - [💡 Why Redis OM?](#-why-redis-om) - [📇 Modeling Your Data](#-modeling-your-data) - [✓ Validating Data With Your Model](#-validating-data-with-your-model) - [🔎 Rich Queries and Embedded Models](#-rich-queries-and-embedded-models) - [Querying](#querying) - [Embedded Models](#embedded-models) - [Calling Other Redis Commands](#calling-other-redis-commands) - [💻 Installation](#-installation) - [📚 Documentation](#-documentation) - [⛏️ Troubleshooting](#️-troubleshooting) - [✨ So How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) - [❤️ Contributing](#️-contributing) - [📝 License](#-license)
## 💡 Why Redis OM? Redis OM provides high-level abstractions that make it easy to model and query data in Redis with modern Python applications. This **preview** release contains the following features: * Declarative object mapping for Redis objects * Declarative secondary-index generation * Fluent APIs for querying Redis ## 📇 Modeling Your Data Redis OM contains powerful declarative models that give you data validation, serialization, and persistence to Redis. Check out this example of modeling customer data with Redis OM. First, we create a `Customer` model: ```python 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] ``` Now that we have a `Customer` model, let's use it to save customer data to Redis. ```python 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() # Expire the model after 2 mins (120 seconds) andrew.expire(120) # To retrieve this customer with its primary key, we use `Customer.get()`: assert Customer.get(andrew.pk) == andrew ``` **Ready to learn more?** Check out the [getting started](docs/getting_started.md) guide. Or, continue reading to see how Redis OM makes data validation a snap. ## ✓ Validating Data With Your Model Redis OM uses [Pydantic][pydantic-url] to validate data based on the type annotations you assign to fields in a model class. This validation ensures that fields like `first_name`, which the `Customer` model marked as a `str`, are always strings. **But every Redis OM model is also a Pydantic model**, so you can use Pydantic validators like `EmailStr`, `Pattern`, and many more for complex validations! For example, because we used the `EmailStr` type for the `email` field, we'll get a validation error if we try to create a `Customer` with an invalid email address: ```python 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) """ ``` **Any existing Pydantic validator should work** as a drop-in type annotation with a Redis OM model. You can also write arbitrarily complex custom validations! To learn more, see the [documentation on data validation](docs/validation.md). ## 🔎 Rich Queries and Embedded Models Data modeling, validation, and saving models to Redis all work regardless of how you run Redis. Next, we'll show you the **rich query expressions** and **embedded models** Redis OM provides when the [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] modules are installed in your Redis deployment, or you're using [Redis Enterprise][redis-enterprise-url]. **TIP**: *Wait, what's a Redis module?* If you aren't familiar with Redis modules, review the [So, How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) section of this README. ### Querying Redis OM comes with a rich query language that allows you to query Redis with Python expressions. To show how this works, we'll make a small change to the `Customer` model we defined earlier. We'll add `Field(index=True)` to tell Redis OM that we want to index the `last_name` and `age` fields: ```python import datetime from typing import Optional from pydantic import EmailStr from redis_om import ( Field, HashModel, Migrator ) 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! Migrator().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() ``` These queries -- and more! -- are possible because **Redis OM manages indexes for you automatically**. Querying with this index features a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee. We think you'll enjoy it! **Note:** Indexing only works for data stored in Redis logical database 0. If you are using a different database number when connecting to Redis, you can expect the code to raise a `MigrationError` when you run the migrator. ### Embedded Models Redis OM can store and query **nested models** like any document database, with the speed and power you get from Redis. Let's see how this works. In the next example, we'll define a new `Address` model and embed it within the `Customer` model. ```python import datetime from typing import Optional from redis_om import ( EmbeddedJsonModel, JsonModel, Field, Migrator, ) 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 # 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! Migrator().run() # Find all customers who live in San Antonio, TX Customer.find(Customer.address.city == "San Antonio", Customer.address.state == "TX") ``` ## Calling Other Redis Commands Sometimes you'll need to run a Redis command directly. Redis OM supports this through the `db` method on your model's class. This returns a connected Redis client instance which exposes a function named for each Redis command. For example, let's perform some basic set operations: ```python from redis_om import HashModel class Demo(HashModel): some_field: str redis_conn = Demo.db() redis_conn.sadd("myset", "a", "b", "c", "d") # Prints False print(redis_conn.sismember("myset", "e")) # Prints True print(redis_conn.sismember("myset", "b")) ``` The parameters expected by each command function are those documented on the command's page on [redis.io](https://redis.io/commands/). If you don't want to get a Redis connection from a model class, you can also use `get_redis_connection`: ```python from redis_om import get_redis_connection redis_conn = get_redis_connection() redis_conn.set("hello", "world") ``` ## 💻 Installation Installation is simple with `pip`, Poetry, or Pipenv. ```sh # With pip $ pip install redis-om # Or, using Poetry $ poetry add redis-om ``` ## 📚 Documentation The Redis OM documentation is available [here](docs/index.md). ## ⛏️ Troubleshooting If you run into trouble or have any questions, we're here to help! Hit us up on the [Redis Discord Server](http://discord.gg/redis) or [open an issue on GitHub](https://github.com/redis-developer/redis-om-python/issues/new). ## ✨ So How Do You Get RediSearch and RedisJSON? Some advanced features of Redis OM rely on core features from two source available Redis modules: [RediSearch][redisearch-url] and [RedisJSON][redis-json-url]. You can run these modules in your self-hosted Redis deployment, or you can use [Redis Enterprise][redis-enterprise-url], which includes both modules. To learn more, read [our documentation](docs/redis_modules.md). ## ❤️ Contributing We'd love your contributions! **Bug reports** are especially helpful at this stage of the project. [You can open a bug report on GitHub](https://github.com/redis/redis-om-python/issues/new). You can also **contribute documentation** -- or just let us know if something needs more detail. [Open an issue on GitHub](https://github.com/redis/redis-om-python/issues/new) to get started. ## 📝 License Redis OM uses the [MIT license][license-url]. [version-svg]: https://img.shields.io/pypi/v/redis-om?style=flat-square [package-url]: https://pypi.org/project/redis-om/ [ci-svg]: https://img.shields.io/github/workflow/status/redis/redis-om-python/CI?style=flat-square [ci-url]: https://github.com/redis/redis-om-python/actions/workflows/CI.yml [license-image]: https://img.shields.io/badge/license-mit-green.svg?style=flat-square [license-url]: LICENSE [redis-om-website]: https://developer.redis.com [redis-om-js]: https://github.com/redis-om/redis-om-js [redis-om-dotnet]: https://github.com/redis-om/redis-om-dotnet [redis-om-spring]: https://github.com/redis-om/redis-om-spring [redisearch-url]: https://redis.io/docs/stack/search/ [redis-json-url]: https://redis.io/docs/stack/json/ [pydantic-url]: https://github.com/samuelcolvin/pydantic [ulid-url]: https://github.com/ulid/spec [redis-enterprise-url]: https://redis.com/try-free/ %package -n python3-redis-om Summary: Object mappings, and more, for Redis. Provides: python-redis-om BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-redis-om [![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Build Status][ci-svg]][ci-url] **Redis OM Python** makes it easy to model Redis data in your Python applications. [Redis OM .NET](https://github.com/redis/redis-om-dotnet) | [Redis OM Node.js](https://github.com/redis/redis-om-node) | [Redis OM Spring](https://github.com/redis/redis-om-spring) | **Redis OM Python**
Table of contents span - [💡 Why Redis OM?](#-why-redis-om) - [📇 Modeling Your Data](#-modeling-your-data) - [✓ Validating Data With Your Model](#-validating-data-with-your-model) - [🔎 Rich Queries and Embedded Models](#-rich-queries-and-embedded-models) - [Querying](#querying) - [Embedded Models](#embedded-models) - [Calling Other Redis Commands](#calling-other-redis-commands) - [💻 Installation](#-installation) - [📚 Documentation](#-documentation) - [⛏️ Troubleshooting](#️-troubleshooting) - [✨ So How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) - [❤️ Contributing](#️-contributing) - [📝 License](#-license)
## 💡 Why Redis OM? Redis OM provides high-level abstractions that make it easy to model and query data in Redis with modern Python applications. This **preview** release contains the following features: * Declarative object mapping for Redis objects * Declarative secondary-index generation * Fluent APIs for querying Redis ## 📇 Modeling Your Data Redis OM contains powerful declarative models that give you data validation, serialization, and persistence to Redis. Check out this example of modeling customer data with Redis OM. First, we create a `Customer` model: ```python 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] ``` Now that we have a `Customer` model, let's use it to save customer data to Redis. ```python 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() # Expire the model after 2 mins (120 seconds) andrew.expire(120) # To retrieve this customer with its primary key, we use `Customer.get()`: assert Customer.get(andrew.pk) == andrew ``` **Ready to learn more?** Check out the [getting started](docs/getting_started.md) guide. Or, continue reading to see how Redis OM makes data validation a snap. ## ✓ Validating Data With Your Model Redis OM uses [Pydantic][pydantic-url] to validate data based on the type annotations you assign to fields in a model class. This validation ensures that fields like `first_name`, which the `Customer` model marked as a `str`, are always strings. **But every Redis OM model is also a Pydantic model**, so you can use Pydantic validators like `EmailStr`, `Pattern`, and many more for complex validations! For example, because we used the `EmailStr` type for the `email` field, we'll get a validation error if we try to create a `Customer` with an invalid email address: ```python 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) """ ``` **Any existing Pydantic validator should work** as a drop-in type annotation with a Redis OM model. You can also write arbitrarily complex custom validations! To learn more, see the [documentation on data validation](docs/validation.md). ## 🔎 Rich Queries and Embedded Models Data modeling, validation, and saving models to Redis all work regardless of how you run Redis. Next, we'll show you the **rich query expressions** and **embedded models** Redis OM provides when the [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] modules are installed in your Redis deployment, or you're using [Redis Enterprise][redis-enterprise-url]. **TIP**: *Wait, what's a Redis module?* If you aren't familiar with Redis modules, review the [So, How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) section of this README. ### Querying Redis OM comes with a rich query language that allows you to query Redis with Python expressions. To show how this works, we'll make a small change to the `Customer` model we defined earlier. We'll add `Field(index=True)` to tell Redis OM that we want to index the `last_name` and `age` fields: ```python import datetime from typing import Optional from pydantic import EmailStr from redis_om import ( Field, HashModel, Migrator ) 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! Migrator().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() ``` These queries -- and more! -- are possible because **Redis OM manages indexes for you automatically**. Querying with this index features a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee. We think you'll enjoy it! **Note:** Indexing only works for data stored in Redis logical database 0. If you are using a different database number when connecting to Redis, you can expect the code to raise a `MigrationError` when you run the migrator. ### Embedded Models Redis OM can store and query **nested models** like any document database, with the speed and power you get from Redis. Let's see how this works. In the next example, we'll define a new `Address` model and embed it within the `Customer` model. ```python import datetime from typing import Optional from redis_om import ( EmbeddedJsonModel, JsonModel, Field, Migrator, ) 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 # 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! Migrator().run() # Find all customers who live in San Antonio, TX Customer.find(Customer.address.city == "San Antonio", Customer.address.state == "TX") ``` ## Calling Other Redis Commands Sometimes you'll need to run a Redis command directly. Redis OM supports this through the `db` method on your model's class. This returns a connected Redis client instance which exposes a function named for each Redis command. For example, let's perform some basic set operations: ```python from redis_om import HashModel class Demo(HashModel): some_field: str redis_conn = Demo.db() redis_conn.sadd("myset", "a", "b", "c", "d") # Prints False print(redis_conn.sismember("myset", "e")) # Prints True print(redis_conn.sismember("myset", "b")) ``` The parameters expected by each command function are those documented on the command's page on [redis.io](https://redis.io/commands/). If you don't want to get a Redis connection from a model class, you can also use `get_redis_connection`: ```python from redis_om import get_redis_connection redis_conn = get_redis_connection() redis_conn.set("hello", "world") ``` ## 💻 Installation Installation is simple with `pip`, Poetry, or Pipenv. ```sh # With pip $ pip install redis-om # Or, using Poetry $ poetry add redis-om ``` ## 📚 Documentation The Redis OM documentation is available [here](docs/index.md). ## ⛏️ Troubleshooting If you run into trouble or have any questions, we're here to help! Hit us up on the [Redis Discord Server](http://discord.gg/redis) or [open an issue on GitHub](https://github.com/redis-developer/redis-om-python/issues/new). ## ✨ So How Do You Get RediSearch and RedisJSON? Some advanced features of Redis OM rely on core features from two source available Redis modules: [RediSearch][redisearch-url] and [RedisJSON][redis-json-url]. You can run these modules in your self-hosted Redis deployment, or you can use [Redis Enterprise][redis-enterprise-url], which includes both modules. To learn more, read [our documentation](docs/redis_modules.md). ## ❤️ Contributing We'd love your contributions! **Bug reports** are especially helpful at this stage of the project. [You can open a bug report on GitHub](https://github.com/redis/redis-om-python/issues/new). You can also **contribute documentation** -- or just let us know if something needs more detail. [Open an issue on GitHub](https://github.com/redis/redis-om-python/issues/new) to get started. ## 📝 License Redis OM uses the [MIT license][license-url]. [version-svg]: https://img.shields.io/pypi/v/redis-om?style=flat-square [package-url]: https://pypi.org/project/redis-om/ [ci-svg]: https://img.shields.io/github/workflow/status/redis/redis-om-python/CI?style=flat-square [ci-url]: https://github.com/redis/redis-om-python/actions/workflows/CI.yml [license-image]: https://img.shields.io/badge/license-mit-green.svg?style=flat-square [license-url]: LICENSE [redis-om-website]: https://developer.redis.com [redis-om-js]: https://github.com/redis-om/redis-om-js [redis-om-dotnet]: https://github.com/redis-om/redis-om-dotnet [redis-om-spring]: https://github.com/redis-om/redis-om-spring [redisearch-url]: https://redis.io/docs/stack/search/ [redis-json-url]: https://redis.io/docs/stack/json/ [pydantic-url]: https://github.com/samuelcolvin/pydantic [ulid-url]: https://github.com/ulid/spec [redis-enterprise-url]: https://redis.com/try-free/ %package help Summary: Development documents and examples for redis-om Provides: python3-redis-om-doc %description help [![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Build Status][ci-svg]][ci-url] **Redis OM Python** makes it easy to model Redis data in your Python applications. [Redis OM .NET](https://github.com/redis/redis-om-dotnet) | [Redis OM Node.js](https://github.com/redis/redis-om-node) | [Redis OM Spring](https://github.com/redis/redis-om-spring) | **Redis OM Python**
Table of contents span - [💡 Why Redis OM?](#-why-redis-om) - [📇 Modeling Your Data](#-modeling-your-data) - [✓ Validating Data With Your Model](#-validating-data-with-your-model) - [🔎 Rich Queries and Embedded Models](#-rich-queries-and-embedded-models) - [Querying](#querying) - [Embedded Models](#embedded-models) - [Calling Other Redis Commands](#calling-other-redis-commands) - [💻 Installation](#-installation) - [📚 Documentation](#-documentation) - [⛏️ Troubleshooting](#️-troubleshooting) - [✨ So How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) - [❤️ Contributing](#️-contributing) - [📝 License](#-license)
## 💡 Why Redis OM? Redis OM provides high-level abstractions that make it easy to model and query data in Redis with modern Python applications. This **preview** release contains the following features: * Declarative object mapping for Redis objects * Declarative secondary-index generation * Fluent APIs for querying Redis ## 📇 Modeling Your Data Redis OM contains powerful declarative models that give you data validation, serialization, and persistence to Redis. Check out this example of modeling customer data with Redis OM. First, we create a `Customer` model: ```python 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] ``` Now that we have a `Customer` model, let's use it to save customer data to Redis. ```python 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() # Expire the model after 2 mins (120 seconds) andrew.expire(120) # To retrieve this customer with its primary key, we use `Customer.get()`: assert Customer.get(andrew.pk) == andrew ``` **Ready to learn more?** Check out the [getting started](docs/getting_started.md) guide. Or, continue reading to see how Redis OM makes data validation a snap. ## ✓ Validating Data With Your Model Redis OM uses [Pydantic][pydantic-url] to validate data based on the type annotations you assign to fields in a model class. This validation ensures that fields like `first_name`, which the `Customer` model marked as a `str`, are always strings. **But every Redis OM model is also a Pydantic model**, so you can use Pydantic validators like `EmailStr`, `Pattern`, and many more for complex validations! For example, because we used the `EmailStr` type for the `email` field, we'll get a validation error if we try to create a `Customer` with an invalid email address: ```python 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) """ ``` **Any existing Pydantic validator should work** as a drop-in type annotation with a Redis OM model. You can also write arbitrarily complex custom validations! To learn more, see the [documentation on data validation](docs/validation.md). ## 🔎 Rich Queries and Embedded Models Data modeling, validation, and saving models to Redis all work regardless of how you run Redis. Next, we'll show you the **rich query expressions** and **embedded models** Redis OM provides when the [RediSearch][redisearch-url] and [RedisJSON][redis-json-url] modules are installed in your Redis deployment, or you're using [Redis Enterprise][redis-enterprise-url]. **TIP**: *Wait, what's a Redis module?* If you aren't familiar with Redis modules, review the [So, How Do You Get RediSearch and RedisJSON?](#-so-how-do-you-get-redisearch-and-redisjson) section of this README. ### Querying Redis OM comes with a rich query language that allows you to query Redis with Python expressions. To show how this works, we'll make a small change to the `Customer` model we defined earlier. We'll add `Field(index=True)` to tell Redis OM that we want to index the `last_name` and `age` fields: ```python import datetime from typing import Optional from pydantic import EmailStr from redis_om import ( Field, HashModel, Migrator ) 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! Migrator().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() ``` These queries -- and more! -- are possible because **Redis OM manages indexes for you automatically**. Querying with this index features a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee. We think you'll enjoy it! **Note:** Indexing only works for data stored in Redis logical database 0. If you are using a different database number when connecting to Redis, you can expect the code to raise a `MigrationError` when you run the migrator. ### Embedded Models Redis OM can store and query **nested models** like any document database, with the speed and power you get from Redis. Let's see how this works. In the next example, we'll define a new `Address` model and embed it within the `Customer` model. ```python import datetime from typing import Optional from redis_om import ( EmbeddedJsonModel, JsonModel, Field, Migrator, ) 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 # 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! Migrator().run() # Find all customers who live in San Antonio, TX Customer.find(Customer.address.city == "San Antonio", Customer.address.state == "TX") ``` ## Calling Other Redis Commands Sometimes you'll need to run a Redis command directly. Redis OM supports this through the `db` method on your model's class. This returns a connected Redis client instance which exposes a function named for each Redis command. For example, let's perform some basic set operations: ```python from redis_om import HashModel class Demo(HashModel): some_field: str redis_conn = Demo.db() redis_conn.sadd("myset", "a", "b", "c", "d") # Prints False print(redis_conn.sismember("myset", "e")) # Prints True print(redis_conn.sismember("myset", "b")) ``` The parameters expected by each command function are those documented on the command's page on [redis.io](https://redis.io/commands/). If you don't want to get a Redis connection from a model class, you can also use `get_redis_connection`: ```python from redis_om import get_redis_connection redis_conn = get_redis_connection() redis_conn.set("hello", "world") ``` ## 💻 Installation Installation is simple with `pip`, Poetry, or Pipenv. ```sh # With pip $ pip install redis-om # Or, using Poetry $ poetry add redis-om ``` ## 📚 Documentation The Redis OM documentation is available [here](docs/index.md). ## ⛏️ Troubleshooting If you run into trouble or have any questions, we're here to help! Hit us up on the [Redis Discord Server](http://discord.gg/redis) or [open an issue on GitHub](https://github.com/redis-developer/redis-om-python/issues/new). ## ✨ So How Do You Get RediSearch and RedisJSON? Some advanced features of Redis OM rely on core features from two source available Redis modules: [RediSearch][redisearch-url] and [RedisJSON][redis-json-url]. You can run these modules in your self-hosted Redis deployment, or you can use [Redis Enterprise][redis-enterprise-url], which includes both modules. To learn more, read [our documentation](docs/redis_modules.md). ## ❤️ Contributing We'd love your contributions! **Bug reports** are especially helpful at this stage of the project. [You can open a bug report on GitHub](https://github.com/redis/redis-om-python/issues/new). You can also **contribute documentation** -- or just let us know if something needs more detail. [Open an issue on GitHub](https://github.com/redis/redis-om-python/issues/new) to get started. ## 📝 License Redis OM uses the [MIT license][license-url]. [version-svg]: https://img.shields.io/pypi/v/redis-om?style=flat-square [package-url]: https://pypi.org/project/redis-om/ [ci-svg]: https://img.shields.io/github/workflow/status/redis/redis-om-python/CI?style=flat-square [ci-url]: https://github.com/redis/redis-om-python/actions/workflows/CI.yml [license-image]: https://img.shields.io/badge/license-mit-green.svg?style=flat-square [license-url]: LICENSE [redis-om-website]: https://developer.redis.com [redis-om-js]: https://github.com/redis-om/redis-om-js [redis-om-dotnet]: https://github.com/redis-om/redis-om-dotnet [redis-om-spring]: https://github.com/redis-om/redis-om-spring [redisearch-url]: https://redis.io/docs/stack/search/ [redis-json-url]: https://redis.io/docs/stack/json/ [pydantic-url]: https://github.com/samuelcolvin/pydantic [ulid-url]: https://github.com/ulid/spec [redis-enterprise-url]: https://redis.com/try-free/ %prep %autosetup -n redis-om-0.1.2 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-redis-om -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Wed May 10 2023 Python_Bot - 0.1.2-1 - Package Spec generated