|
| 1 | +import asyncio |
| 2 | +import json |
| 3 | +from datetime import date |
| 4 | +from datetime import datetime |
| 5 | +from typing import Any |
| 6 | +from typing import Dict |
| 7 | +from typing import List |
| 8 | +from typing import Optional |
| 9 | + |
| 10 | +from pydantic_aioredis import Model |
| 11 | +from pydantic_aioredis import RedisConfig |
| 12 | +from pydantic_aioredis import Store |
| 13 | +from pydantic_aioredis.abstract import STR_DUMP_SHAPES |
| 14 | + |
| 15 | + |
| 16 | +class BookCover: |
| 17 | + def __init__(self, cover_url: int, cover_size_x: int, cover_size_y: int): |
| 18 | + self.cover_url = cover_url |
| 19 | + self.cover_size_x = cover_size_x |
| 20 | + self.cover_size_y = cover_size_y |
| 21 | + |
| 22 | + @property |
| 23 | + def area(self): |
| 24 | + return self.cover_size_x * self.cover_size_y |
| 25 | + |
| 26 | + |
| 27 | +# Create models as you would create pydantic models i.e. using typings |
| 28 | +class Book(Model): |
| 29 | + _primary_key_field: str = "title" |
| 30 | + title: str |
| 31 | + author: str |
| 32 | + published_on: date |
| 33 | + cover: BookCover |
| 34 | + |
| 35 | + @classmethod |
| 36 | + def json_default(cls, obj: Any) -> str: |
| 37 | + """Since BookCover can't be directly json serialized, we have to write our own json_default to serialize it methods to handle it.""" |
| 38 | + if isinstance(obj, BookCover): |
| 39 | + return { |
| 40 | + "__BookCover__": True, |
| 41 | + "cover_url": obj.cover_url, |
| 42 | + "cover_size_x": obj.cover_size_x, |
| 43 | + "cover_size_y": obj.cover_size_y, |
| 44 | + } |
| 45 | + |
| 46 | + return super().json_default(obj) |
| 47 | + |
| 48 | + @classmethod |
| 49 | + def json_object_hook(cls, obj: dict): |
| 50 | + """Since we're serializing BookCovers above, we need to write an object hook to turn them back into an Object""" |
| 51 | + if obj.get("__BookCover__", False): |
| 52 | + return BookCover( |
| 53 | + cover_url=obj["cover_url"], |
| 54 | + cover_size_x=obj["cover_size_x"], |
| 55 | + cover_size_y=obj["cover_size_y"], |
| 56 | + ) |
| 57 | + super().json_object_hook(obj) |
| 58 | + |
| 59 | + |
| 60 | +# Redisconfig. Change this configuration to match your redis server |
| 61 | +redis_config = RedisConfig( |
| 62 | + db=5, host="localhost", password="password", ssl=False, port=6379 |
| 63 | +) |
| 64 | + |
| 65 | + |
| 66 | +# Create the store and register your models |
| 67 | +store = Store(name="some_name", redis_config=redis_config, life_span_in_seconds=3600) |
| 68 | +store.register_model(Book) |
| 69 | + |
| 70 | + |
| 71 | +# Sample books. You can create as many as you wish anywhere in the code |
| 72 | +books = [ |
| 73 | + Book( |
| 74 | + title="Oliver Twist", |
| 75 | + author="Charles Dickens", |
| 76 | + published_on=date(year=1215, month=4, day=4), |
| 77 | + cover=BookCover( |
| 78 | + "https://images-na.ssl-images-amazon.com/images/I/51SmEM7LUGL._SX342_SY445_QL70_FMwebp_.jpg", |
| 79 | + 333, |
| 80 | + 499, |
| 81 | + ), |
| 82 | + ), |
| 83 | + Book( |
| 84 | + title="Great Expectations", |
| 85 | + author="Charles Dickens", |
| 86 | + published_on=date(year=1220, month=4, day=4), |
| 87 | + cover=BookCover( |
| 88 | + "https://images-na.ssl-images-amazon.com/images/I/51i715XqsYL._SX311_BO1,204,203,200_.jpg", |
| 89 | + 333, |
| 90 | + 499, |
| 91 | + ), |
| 92 | + ), |
| 93 | + Book( |
| 94 | + title="Jane Eyre", |
| 95 | + author="Charlotte Bronte", |
| 96 | + published_on=date(year=1225, month=6, day=4), |
| 97 | + cover=BookCover( |
| 98 | + "https://images-na.ssl-images-amazon.com/images/I/41saarVx+GL._SX324_BO1,204,203,200_.jpg", |
| 99 | + 333, |
| 100 | + 499, |
| 101 | + ), |
| 102 | + ), |
| 103 | + Book( |
| 104 | + title="Wuthering Heights", |
| 105 | + author="Emily Bronte", |
| 106 | + published_on=date(year=1600, month=4, day=4), |
| 107 | + cover=BookCover( |
| 108 | + "https://images-na.ssl-images-amazon.com/images/I/51ZKox7zBKL._SX338_BO1,204,203,200_.jpg", |
| 109 | + 333, |
| 110 | + 499, |
| 111 | + ), |
| 112 | + ), |
| 113 | +] |
| 114 | + |
| 115 | + |
| 116 | +async def work_with_orm(): |
| 117 | + # Insert them into redis |
| 118 | + await Book.insert(books) |
| 119 | + |
| 120 | + # Select all books to view them. A list of Model instances will be returned |
| 121 | + all_books = await Book.select() |
| 122 | + print(all_books) # Will print [Book(title="Oliver Twist", author="Charles Dickens", |
| 123 | + # published_on=date(year=1215, month=4, day=4), in_stock=False), Book(...] |
| 124 | + |
| 125 | + # Or select some of the books |
| 126 | + some_books = await Book.select(ids=["Oliver Twist", "Jane Eyre"]) |
| 127 | + print(some_books) # Will return only those two books |
| 128 | + |
| 129 | + # Or select some of the columns. THIS RETURNS DICTIONARIES not MODEL Instances |
| 130 | + # The Dictionaries have values in string form so you might need to do some extra work |
| 131 | + books_with_few_fields = await Book.select(columns=["author", "cover"]) |
| 132 | + print( |
| 133 | + books_with_few_fields |
| 134 | + ) # Will print [{"author": "'Charles Dickens", "covker": Cover},...] |
| 135 | + |
| 136 | + # When _auto_sync = True (default), updating any attribute will update that field in Redis too |
| 137 | + this_book = Book( |
| 138 | + title="Moby Dick", |
| 139 | + author="Herman Melvill", |
| 140 | + published_on=date(year=1851, month=10, day=18), |
| 141 | + cover=BookCover( |
| 142 | + "https://m.media-amazon.com/images/I/411a8Moy1mL._SY346_.jpg", 333, 499 |
| 143 | + ), |
| 144 | + ) |
| 145 | + await Book.insert(this_book) |
| 146 | + # oops, there was a typo. Fix it |
| 147 | + this_book.author = "Herman Melville" |
| 148 | + this_book_from_redis = await Book.select(ids=["Moby Dick"]) |
| 149 | + assert this_book_from_redis[0].author == "Herman Melville" |
| 150 | + |
| 151 | + # If you have _auto_save set to false on a model, you have to await .save() to update a model in tedis |
| 152 | + await this_book.save() |
| 153 | + |
| 154 | + |
| 155 | +if __name__ == "__main__": |
| 156 | + asyncio.run(work_with_orm()) |
0 commit comments