With Redis OM, you get powerful data modeling, extensible data validation with [Pydantic](pydantic-url), 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.
```python
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](https://redis.io/topics/data-types).
Next, let's see how Redis OM makes it easy to save and retrieve `Customer` data in Redis.
```python
# 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:
# 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](https://pydantic-docs.helpmanual.io/usage/types/). 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.
```python
# 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](redis-json-url) 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](ulid-url))
Ready to learn more? Read the [getting started](docs/getting_started.md) guide or check out how to [add Redis OM to your FastAPI project](docs/integrating.md).
**Bug reports** are especially helpful at this stage of the project. [You can open a bug report on GitHub](https://github.com/redis-om/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-om/redis-om-python/issues/new) to get started.