Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ README.md
Redi
RediSearch
RediSearch
RedisInsight
RedisJSON
SQLAlchemy
SSL
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ redis_conn.set("hello", "world")

## 📚 Documentation

The Redis OM documentation is available [here](docs/index.md).
The Redis OM documentation is available at **[redis.github.io/redis-om-python](https://redis.github.io/redis-om-python/)**.

## ⛏️ Troubleshooting

Expand All @@ -366,7 +366,7 @@ Some advanced features of Redis OM rely on core features from two source availab

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).
To learn more, read [our documentation](docs/redis_setup.md).

## Connecting to Azure Managed Redis with EntraID

Expand Down
100 changes: 0 additions & 100 deletions docs/connections.md

This file was deleted.

68 changes: 40 additions & 28 deletions docs/fastapi_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,26 @@ class Customer(HashModel):
bio: Optional[str]


app = FastAPI()
from contextlib import asynccontextmanager


@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Initialize cache and Redis OM connection
r = redis.asyncio.from_url(REDIS_CACHE_URL, encoding="utf8",
decode_responses=True)
FastAPICache.init(RedisBackend(r), prefix="fastapi-cache")

# You can set the Redis OM URL using the REDIS_OM_URL environment
# variable, or by manually creating the connection using your model's
# Meta object.
Customer.Meta.database = get_redis_connection(url=REDIS_DATA_URL,
decode_responses=True)
yield
# Shutdown: cleanup if needed


app = FastAPI(lifespan=lifespan)


@app.post("/customer")
Expand All @@ -90,19 +109,6 @@ async def get_customer(pk: str, request: Request, response: Response):
return Customer.get(pk)
except NotFoundError:
raise HTTPException(status_code=404, detail="Customer not found")


@app.on_event("startup")
async def startup():
r = redis.asyncio.from_url(REDIS_CACHE_URL, encoding="utf8",
decode_responses=True)
FastAPICache.init(RedisBackend(r), prefix="fastapi-cache")

# You can set the Redis OM URL using the REDIS_OM_URL environment
# variable, or by manually creating the connection using your model's
# Meta object.
Customer.Meta.database = get_redis_connection(url=REDIS_DATA_URL,
decode_responses=True)
```

## Testing the app
Expand Down Expand Up @@ -179,7 +185,26 @@ class Customer(HashModel):
bio: Optional[str]


app = FastAPI()
from contextlib import asynccontextmanager


@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Initialize cache and Redis OM connection
r = redis.asyncio.from_url(REDIS_CACHE_URL, encoding="utf8",
decode_responses=True)
FastAPICache.init(RedisBackend(r), prefix="fastapi-cache")

# You can set the Redis OM URL using the REDIS_OM_URL environment
# variable, or by manually creating the connection using your model's
# Meta object.
Customer.Meta.database = get_redis_connection(url=REDIS_DATA_URL,
decode_responses=True)
yield
# Shutdown: cleanup if needed


app = FastAPI(lifespan=lifespan)


@app.post("/customer")
Expand All @@ -202,19 +227,6 @@ async def get_customer(pk: str, request: Request, response: Response):
return await Customer.get(pk) # <- And, finally, one more await!
except NotFoundError:
raise HTTPException(status_code=404, detail="Customer not found")


@app.on_event("startup")
async def startup():
r = redis.asyncio.from_url(REDIS_CACHE_URL, encoding="utf8",
decode_responses=True)
FastAPICache.init(RedisBackend(r), prefix="fastapi-cache")

# You can set the Redis OM URL using the REDIS_OM_URL environment
# variable, or by manually creating the connection using your model's
# Meta object.
Customer.Meta.database = get_redis_connection(url=REDIS_DATA_URL,
decode_responses=True)
```

**NOTE:** The modules `redis_om` and `aredis_om` are identical in almost every
Expand Down
69 changes: 42 additions & 27 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,24 @@ The command to start Redis with Docker depends on the image you've chosen to use

**TIP:** The `-d` option in these examples runs Redis in the background, while `-p 6379:6379` makes Redis reachable at port 6379 on your localhost.

#### Docker with the `redismod` image (recommended)
#### Docker with Redis 8 (recommended)

$ docker run -d -p 6379:6379 redislabs/redismod
$ docker run -d -p 6379:6379 redis:8

### Docker with the `redis` image
Redis 8 includes the Search and JSON capabilities needed for full Redis OM functionality.

#### Docker with Redis Stack

$ docker run -d -p 6379:6379 redis/redis-stack

Redis Stack also includes the Search and JSON capabilities.

#### Docker with the basic `redis` image

$ docker run -d -p 6379:6379 redis

**NOTE:** The basic Redis image does not include Search and JSON capabilities. You can still use Redis OM for data modeling and persistence, but `JsonModel` and the `find()` query interface won't work.

## Installing Redis OM

The recommended way to install Redis OM is with [Poetry](https://python-poetry.org/docs/). You can install Redis OM using Poetry with the following command:
Expand Down Expand Up @@ -239,9 +249,9 @@ try:
except ValidationError as e:
print(e)
"""
ValidationError: 1 validation error for Customer
1 validation error for Customer
bio
field required (type=value_error.missing)
Field required [type=missing, input_value={'first_name': 'Andrew',..._date': datetime.date...}, input_type=dict]
"""
```

Expand Down Expand Up @@ -389,9 +399,9 @@ try:
except ValidationError as e:
print(e)
"""
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
1 validation error for Customer
join_date
invalid date format (type=value_error.date)
Input should be a valid date or datetime [type=date_from_datetime_parsing, ...]
"""
```

Expand Down Expand Up @@ -471,9 +481,9 @@ try:
except ValidationError as e:
print(e)
"""
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
1 validation error for Customer
age
Value is not a valid integer (type=type_error.integer)
Input should be a valid integer [type=int_type, ...]
"""
```

Expand All @@ -487,13 +497,22 @@ from pydantic import ValidationError
from redis_om import HashModel


from typing import Annotated, Any
from pydantic import GetCoreSchemaHandler
from pydantic_core import CoreSchema, core_schema


class StrictDate(datetime.date):
"""A strict date type that doesn't allow string coercion."""

@classmethod
def __get_validators__(cls) -> 'CallableGenerator':
yield cls.validate
def __get_pydantic_core_schema__(
cls, source_type: Any, handler: GetCoreSchemaHandler
) -> CoreSchema:
return core_schema.no_info_plain_validator_function(cls.validate)

@classmethod
def validate(cls, value: datetime.date, **kwargs) -> datetime.date:
def validate(cls, value: Any) -> datetime.date:
if not isinstance(value, datetime.date):
raise ValueError("Value must be a datetime.date object")
return value
Expand All @@ -516,14 +535,14 @@ try:
last_name="Brookins",
email="a@example.com",
join_date="2020-01-02", # <- A string shouldn't work now!
age="38"
age=38
)
except ValidationError as e:
print(e)
"""
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
1 validation error for Customer
join_date
Value must be a datetime.date object (type=value_error)
Value error, Value must be a datetime.date object [type=value_error, ...]
"""
```

Expand Down Expand Up @@ -670,11 +689,10 @@ from pydantic import EmailStr
from redis_om import (
Field,
HashModel,
Migrator
)


class Customer(HashModel):
class Customer(HashModel, index=True):
first_name: str
last_name: str = Field(index=True)
email: EmailStr
Expand All @@ -687,9 +705,8 @@ class Customer(HashModel):
# 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 `om migrate`
# CLI tool for this!
Migrator().run()
# indexes that Redis OM will use. Run the `om migrate` CLI tool:
# $ om migrate

# Find all customers with the last name "Brookins"
Customer.find(Customer.last_name == "Brookins").all()
Expand All @@ -710,16 +727,14 @@ For historical reasons, saving and querying Boolean values is not supported in `
you may store and query Boolean values using the `==` syntax:

```python
from redis_om import (
Field,
JsonModel,
Migrator
)
from redis_om import Field, JsonModel


class Demo(JsonModel):
class Demo(JsonModel, index=True):
b: bool = Field(index=True)

Migrator().run()

# Run migrations first with: om migrate
d = Demo(b=True)
d.save()
res = Demo.find(Demo.b == True)
Expand Down
Loading
Loading