• Stars
    star
    982
  • Rank 44,728 (Top 1.0 %)
  • Language
    Python
  • License
    MIT License
  • Created over 2 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Object mapping, and more, for Redis and Python


Redis OM

Object mapping, and more, for Redis and Python


Version License Build Status

Redis OM Python makes it easy to model Redis data in your Python applications.

Redis OM .NET | Redis OM Node.js | Redis OM Spring | Redis OM Python

Table of contents

span

πŸ’‘ 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

πŸ’» Installation

Installation is simple with pip, Poetry, or Pipenv.

# With pip
$ pip install redis-om

# Or, using Poetry
$ poetry add redis-om

🏁 Getting started

Starting Redis

Before writing any code you'll need a Redis instance with the appropriate Redis modules! The quickest way to get this is with Docker:

docker run -p 6379:6379 -p 8001:8001 redis/redis-stack

This launches the redis-stack an extension of Redis that adds all manner of modern data structures to Redis. You'll also notice that if you open up http://localhost:8001 you'll have access to the redis-insight GUI, a GUI you can use to visualize and work with your data in 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:

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.

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="[email protected]",
    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 guide.

Or, continue reading to see how Redis OM makes data validation a snap.

βœ“ Validating Data With Your Model

Redis OM uses Pydantic 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:

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.

πŸ”Ž 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 and RedisJSON modules are installed in your Redis deployment, or you're using Redis Enterprise.

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? 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:

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.

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:

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.

If you don't want to get a Redis connection from a model class, you can also use get_redis_connection:

from redis_om import get_redis_connection

redis_conn = get_redis_connection()
redis_conn.set("hello", "world")

πŸ“š Documentation

The Redis OM documentation is available here.

⛏️ Troubleshooting

If you run into trouble or have any questions, we're here to help!

Hit us up on the Redis Discord Server or open an issue on GitHub.

✨ 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 and RedisJSON.

You can run these modules in your self-hosted Redis deployment, or you can use Redis Enterprise, which includes both modules.

To learn more, read our documentation.

❀️ 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.

You can also contribute documentation -- or just let us know if something needs more detail. Open an issue on GitHub to get started.

πŸ“ License

Redis OM uses the MIT license.

More Repositories

1

redis

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.
C
64,881
star
2

go-redis

Redis Go client
Go
19,143
star
3

node-redis

Redis Node.js client
TypeScript
16,619
star
4

ioredis

πŸš€ A robust, performance-focused, and full-featured Redis client for Node.js.
TypeScript
13,878
star
5

redis-py

Redis Python Client
Python
12,153
star
6

jedis

Redis Java client
Java
11,542
star
7

hiredis

Minimalistic C client for Redis >= 1.2
C
6,040
star
8

redis-rb

A Ruby client library for Redis
Ruby
3,942
star
9

redis-doc

Redis documentation source code for markdown and metadata files, conversion scripts, and so forth
Shell
2,304
star
10

rueidis

A fast Golang Redis client that supports Client Side Caching, Auto Pipelining, Generics OM, RedisJSON, RedisBloom, RediSearch, etc.
Go
2,150
star
11

redis-om-node

Object mapping, and more, for Redis and Node.js. Written in TypeScript.
TypeScript
1,092
star
12

redis-io

Application running http://redis.io
Ruby
637
star
13

redis-om-spring

Spring Data Redis extensions for better search, documents models, and more
Java
552
star
14

hiredis-py

Python wrapper for hiredis
C
486
star
15

redis-om-dotnet

Object mapping, and more, for Redis and .NET
C#
419
star
16

hiredis-rb

Ruby wrapper for hiredis
Ruby
317
star
17

hiredis-node

Node wrapper for hiredis
JavaScript
304
star
18

riot

🧨 Get data in & out of Redis with RIOT
Java
227
star
19

NRedisStack

Redis Stack .Net client
C#
174
star
20

redis-rcp

Redis Change Proposals
138
star
21

redis-hashes

Redis tarball SHA1 hashes
86
star
22

redis-specifications

A bin for Redis' specs
33
star
23

redis-benchmarks-specification

The Redis benchmarks specification describes the cross-language/tools requirements and expectations to foster performance and observability standards around redis related technologies. Members from both industry and academia, including organizations and individuals are encouraged to contribute.
Python
24
star
24

redis-debian

Debian packaging
Shell
16
star
25

librdb

Redis RDB file parser, with JSON, RESP and RDB-loader extensions
C
16
star
26

redis-snap

A repository for snap packaging
10
star
27

redis-website

HTML
9
star
28

docs

Documentation for Redis, Redis Cloud, and Redis Enterprise
Python
8
star
29

redis-clinterwebz

Python
4
star
30

redis-extra-ci

4
star
31

redis-rpm

Shell
2
star