redis-om-python with updated dependencies
Find a file
2021-10-22 12:20:44 -07:00
.github Remove edge image from testing matrix 2021-10-22 12:20:44 -07:00
docs WIP on README 2021-10-22 08:31:08 -07:00
redis_om WIP on README 2021-10-22 08:31:08 -07:00
tests Fix linting 2021-10-22 09:19:06 -07:00
.gitignore Add building, linting for PyPI upload 2021-10-22 06:53:39 -07:00
CONTRIBUTING.md WIP on README - first draft 2021-10-19 15:06:50 -07:00
demo.py WIP on README 2021-10-22 08:31:08 -07:00
docker-compose.yml Refine connection strings (dotenv), Makefile targets 2021-10-20 14:29:31 -07:00
LICENSE Change to BSD 3-clause license 2021-10-22 06:34:59 -07:00
Makefile Add building, linting for PyPI upload 2021-10-22 06:53:39 -07:00
poetry.lock WIP on README 2021-10-22 08:31:08 -07:00
pyproject.toml WIP on README 2021-10-22 08:31:08 -07:00
README.md WIP on README 2021-10-22 08:31:08 -07:00

Redis OM

Objecting mapping and more, for Redis.


Version License Build Status

Redis OM is a library that helps you build modern Python applications with Redis.

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

Table of contents

➡ Why Redis OM?

Redis OM is a library of high-level tools that help you build modern Python applications with Redis.

This preview release includes our first major component: a declarative model class backed by Redis.

🏁 Getting started

Object Mapping

With Redis OM, you get powerful data modeling, extensible data validation with Pydantic, and rich query expressions with a small amount of code.

Check out this example of data modeling and validation. First, we're going to create a Customer model that we can use to save data to Redis.

import datetime
from typing import Optional

from pydantic import EmailStr

from redis_om.model import (
    HashModel,
)


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

Here, we've defined a Customer model with the HashModel class from redis-om. This model will save data in Redis as a Redis Hash.

Next, let's see how Redis OM makes it easy to save and retrieve Customer data in Redis.

# We can 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.
andrew.save()

# Now, we can retrieve this customer with its primary key:
other_andrew = Customer.get('01FJM6PH661HCNNRC884H6K30C')

# The original model and this one pass an equality check.
assert other_andrew == andrew

Now, let's talk about validation. Did you notice the type annotation for the email field was EmailStr?

EmailStr is a Pydantic field validator. Because every Redis OM model is also a Pydantic model, you can use Pydantic validators like EmailStr, Pattern, and many more!

Let's see what happens if we try to instantiate our Customer class with an invalid email address.

# We'll get a validation error if we try to use an invalid email address!
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."
)
# Traceback:
# pydantic.error_wrappers.ValidationError: 1 validation error for Customer
# email
#   value is not a valid email address (type=value_error.email)

# We'll also get a validation error if we try to save a model
# instance with an invalid email.
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."
)

# Sometime later...
andrew.email = "Not valid"
andrew.save()

# Traceback:
# pydantic.error_wrappers.ValidationError: 1 validation error for Customer
# email
#   value is not a valid email address (type=value_error.email)

Data modeling, validation, and persistent to Redis all work regardless of where you run Redis. But can we do more?

Yes, we can! Next, we'll talk about the rich query expressions and embedded models that Redis OM gives you when you're using the RediSearch and RedisJSON Redis modules.

Querying

Querying uses a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee.

The example code defines Address and Customer models for use with a Redis database with the RedisJSON module installed.

With these two classes defined, you can now:

  • Validate data based on the model's type annotations using Pydantic
  • Persist model instances to Redis as JSON
  • Instantiate model instances from Redis by primary key (a client-generated ULID)
  • Query on any indexed fields in the models
import datetime
from typing import Optional

from redis_om.model import (
    EmbeddedJsonModel,
    JsonModel,
    Field,
)

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

Here are a few example queries that use the models we defined earlier:

# 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()

# Find all customers who live in San Antonio, TX
Customer.find(Customer.address.city == "San Antonio",
              Customer.address.state == "TX")

Ready to learn more? Read the getting started guide or check out how to add Redis OM to your FastAPI project.

💻 Installation

Installation is simple with pip, Poetry, or Pipenv.

# With pip
$ pip install redis-om

# Or, using Poetry
$ poetry add redis-om

📚 Documentation

Documentation is available here.

⛏️ Troubleshooting

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

First, check the FAQ. If you don't find the answer there, hit us up on the Redis Discord Server.

RediSearch and RedisJSON

Some advanced features of Redis OM rely on core features from two source available Redis modules: RediSearch and RedisJSON.

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 BSD 3-Clause license.