🪴 Daily gardening

Search

Search IconIcon to open search

Redis OM Python

Last updated Jan 4, 2023

# 설치하기

1
2
3
4
5
# With pip
$ pip install redis-om

# Or, using Poetry
$ poetry add redis-om

# Redis 연결

1
2
3
4
5
6
7
# Model마다 redis connection을 연결하는 경우
Customer.Meta.database = get_redis_connection(url="redis://localhost:6379",
                          decode_responses=True))

# 전체 같은 redis connection인 경우 
redis = get_redis_connection()
Migrator(redis).run()

# Base models 만들기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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]

andrew = Customer( # 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."
)

# 모델은 unique PK를 자동으로 생성한다.
print(andrew.pk) # (Redis 통신 따로 필요 없음.)
# > '01FJM6PH661HCNNRC884H6K30C'

# `save()` 호출로 Redis에 모델 저장 
andrew.save()

# pk로 Customer 에서 객체를 찾을 수도 있다.
assert Customer.get(andrew.pk)  andrew
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Customer(HashModel):
	#  `:{package}:{class_name}:{first_name}` 으로 키가 생성된다.
	first_name: str = Field(primary_key=True) 
	last_name: str
	email: EmailStr
	join_date: datetime.date
	age: int
	bio: Optional[str]

...
Customer.get(f"{first_name}") # PK로 쿼리시 지정 PK로 찾을 수 있다. 

# Globally unique primary keys

# BaseModel Meta class

기본적으로 :{package}:{class_name}:{pk} 의 키 구조를 갖고 있기 때문에, 나중에 리팩토링으로 인하여 파일의 위치가 변경되거나 class의 이름이 변하게 되면 데이터를 찾을때 찾기 어려울 수 있다. 이를 대비하여, 나에게 맞는 key 네이밍으로 생성할 수 있다. Base Model의 기본 Meta class릴 보면 다음과 같은 모양으로 되어있으며 필요에 따라 세팅해주면 된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@dataclasses.dataclass
class DefaultMeta:
	global_key_prefix: Optional[str] = None
	model_key_prefix: Optional[str] = None
	primary_key_pattern: Optional[str] = None
	database: Optional[redis.Redis] = None
	primary_key: Optional[PrimaryKey] = None
	primary_key_creator_cls: Optional[Type[PrimaryKeyCreator]] = None
	index_name: Optional[str] = None
	embedded: Optional[bool] = False
	encoding: str = "utf-8"

class Customer(HashModel):
	first_name: str
	last_name: str
	...

	Class Meta:
		global_key_prefix = "cheese_project"
		model_key_prefix = "helloworld" 
		primary_key_pattern = "customer:{pk}" 

# Data validation with Pydantic

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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)
	"""

# Query expressions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from redis_om import get_redis_connection

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]

# last name이 "Brookins" 인 모든 customers
Customer.find(Customer.last_name  "Brookins").all()

# Embedded model

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from redis_om 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="")
	address: Address

# "San Antonio, TX"에 사는 모든 customers 구하기 
Customer.find(Customer.address.city  "San Antonio",
				Customer.address.state  "TX")

# 다른 Redis 명령어 사용하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from redis_om import HashModel

class Demo(HashModel):
    some_field: str

redis_conn = Demo.db()
redis_conn.sadd("myset", "a", "b", "c", "d")

print(redis_conn.sismember("myset", "e")) # False
print(redis_conn.sismember("myset", "b")) # True

# Asynchronous 하게 사용하기

Redis OM은 Asyncio도 모두 지원하고 있다.

1
2
3
# asynchronously
from aredis_om import HashModel, NotFoundError  
from aredis_om import get_redis_connection
1
2
3
4
5
6
7
from aredis_om import HashModel

class Customer(HashModel):
	first_name: str
	...

await Customer.all_pks()

# Redis Cluster에서 사용하기

AWS MemoryDB 와 같은 상용 서비스를 사용할 경우, 혹은 가용성을 위하여 Redis cluster 구성하여 사용하는 경우는 아래와 같이 Redis Client를 직접 주입해주면 된다.

1
2
3
4
5
6
7
8
9
from redis.asyncio.cluster import RedisCluster as AsyncRedisCluster


REDIS_DATA_URL = f"rediss://{app_settings.redis_user}:{app_settings.redis_password}@{app_settings.redis_endpoint}:{app_settings.redis_port}"
self._redis_cluster = AsyncRedisCluster.from_url(REDIS_DATA_URL,
												decode_responses=True,
												require_full_coverage=False)

Customer.Meta.database = self._redis_cluster

# References