Package: redis-om
Object mapping, and more, for Redis and PythonRedis OM Pythonmakes it easy to model Redis data in your Python applications.Redis OM .NET|Redis OM Node.js|Redis OM Spring|Redis OM PythonTable of contentsspan💡 Why Redis OM?💻 Installation🏁 Getting started📇 Modeling Your Data✓ Validating Data With Your Model🔎 Rich Queries and Embedded ModelsQueryingEmbedded ModelsCalling Other Redis Commands📚 Documentation⛏️ Troubleshooting✨ So How Do You Get RediSearch and RedisJSON?❤️ Contributing📝 License💡 Why Redis OM?Redis OM provides high-level abstractions that make it easy to model and query data in Redis with modern Python applications.Thispreviewrelease contains the following features:Declarative object mapping for Redis objectsDeclarative secondary-index generationFluent APIs for querying Redis💻 InstallationInstallation is simple withpip, Poetry, or Pipenv.# With pip$pipinstallredis-om# Or, using Poetry$poetryaddredis-om🏁 Getting startedStarting RedisBefore writing any code you'll need a Redis instance with the appropriate Redis modules! The quickest way to get this is with Docker:dockerrun-p6379:6379-p8001:8001redis/redis-stackThis launches theredis-stackan extension of Redis that adds all manner of modern data structures to Redis. You'll also notice that if you open uphttp://localhost:8001you'll have access to the redis-insight GUI, a GUI you can use to visualize and work with your data in Redis.📇 Modeling Your DataRedis 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 aCustomermodel:importdatetimefromtypingimportOptionalfrompydanticimportEmailStrfromredis_omimportHashModelclassCustomer(HashModel):first_name:strlast_name:stremail:EmailStrjoin_date:datetime.dateage:intbio:Optional[str]Now that we have aCustomermodel, let's use it to save customer data to Redis.importdatetimefromtypingimportOptionalfrompydanticimportEmailStrfromredis_omimportHashModelclassCustomer(HashModel):first_name:strlast_name:stremail:EmailStrjoin_date:datetime.dateage:intbio:Optional[str]# First, we 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 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()`:assertCustomer.get(andrew.pk)==andrewReady to learn more?Check out thegetting startedguide.Or, continue reading to see how Redis OM makes data validation a snap.✓ Validating Data With Your ModelRedis OM usesPydanticto validate data based on the type annotations you assign to fields in a model class.This validation ensures that fields likefirst_name, which theCustomermodel marked as astr, are always strings.But every Redis OM model is also a Pydantic model, so you can use Pydantic validators likeEmailStr,Pattern, and many more for complex validations!For example, because we used theEmailStrtype for theemailfield, we'll get a validation error if we try to create aCustomerwith an invalid email address:importdatetimefromtypingimportOptionalfrompydanticimportEmailStr,ValidationErrorfromredis_omimportHashModelclassCustomer(HashModel):first_name:strlast_name:stremail:EmailStrjoin_date:datetime.dateage:intbio: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.")exceptValidationErrorase:print(e)"""pydantic.error_wrappers.ValidationError: 1 validation error for Customeremailvalue is not a valid email address (type=value_error.email)"""Any existing Pydantic validator should workas a drop-in type annotation with a Redis OM model. You can also write arbitrarily complex custom validations!To learn more, see thedocumentation on data validation.🔎 Rich Queries and Embedded ModelsData modeling, validation, and saving models to Redis all work regardless of how you run Redis.Next, we'll show you therich query expressionsandembedded modelsRedis OM provides when theRediSearchandRedisJSONmodules are installed in your Redis deployment, or you're usingRedis Enterprise.TIP:Wait, what's a Redis module?If you aren't familiar with Redis modules, review theSo, How Do You Get RediSearch and RedisJSON?section of this README.QueryingRedis 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 theCustomermodel we defined earlier. We'll addField(index=True)to tell Redis OM that we want to index thelast_nameandagefields:importdatetimefromtypingimportOptionalfrompydanticimportEmailStrfromredis_omimport(Field,HashModel,Migrator)classCustomer(HashModel):first_name:strlast_name:str=Field(index=True)email:EmailStrjoin_date:datetime.dateage: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 becauseRedis 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 aMigrationErrorwhen you run the migrator.Embedded ModelsRedis OM can store and querynested modelslike 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 newAddressmodel and embed it within theCustomermodel.importdatetimefromtypingimportOptionalfromredis_omimport(EmbeddedJsonModel,JsonModel,Field,Migrator,)classAddress(EmbeddedJsonModel):address_line_1:straddress_line_2:Optional[str]city:str=Field(index=True)state:str=Field(index=True)country:strpostal_code:str=Field(index=True)classCustomer(JsonModel):first_name:str=Field(index=True)last_name:str=Field(index=True)email:str=Field(index=True)join_date:datetime.dateage: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, TXCustomer.find(Customer.address.city=="San Antonio",Customer.address.state=="TX")Calling Other Redis CommandsSometimes you'll need to run a Redis command directly.  Redis OM supports this through thedbmethod 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:fromredis_omimportHashModelclassDemo(HashModel):some_field:strredis_conn=Demo.db()redis_conn.sadd("myset","a","b","c","d")# Prints Falseprint(redis_conn.sismember("myset","e"))# Prints Trueprint(redis_conn.sismember("myset","b"))The parameters expected by each command function are those documented on the command's page onredis.io.If you don't want to get a Redis connection from a model class, you can also useget_redis_connection:fromredis_omimportget_redis_connectionredis_conn=get_redis_connection()redis_conn.set("hello","world")📚 DocumentationThe Redis OM documentation is availablehere.⛏️ TroubleshootingIf you run into trouble or have any questions, we're here to help!Hit us up on theRedis Discord Serveroropen 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:RediSearchandRedisJSON.You can run these modules in your self-hosted Redis deployment, or you can useRedis Enterprise, which includes both modules.To learn more, readour documentation.❤️ ContributingWe'd love your contributions!Bug reportsare especially helpful at this stage of the project.You can open a bug report on GitHub.You can alsocontribute documentation-- or just let us know if something needs more detail.Open an issue on GitHubto get started.📝 LicenseRedis OM uses theMIT license.