Python 實現 Redis ORM

2021-12-31 Python程式設計師


議題

我們來為 Redis 寫一個簡單而優雅的 ORM。這篇文章的靈感來自於 Django ORM。

這篇文章假定你對 Redis 以及 Python 中的 redis 庫 redis-py 有了基本的了解。

實體

假設我們正在開發一個輪詢應用程式,這個應用包括 Question 和 Choice。每一個問題都有多個選項。

我們希望在我們的應用程式中具有以下能力:

存儲問題列表並檢索

根據 id 檢索問題

存儲選項

關聯問題與選項列表

將問題與選項取消關聯

檢索一個問題的所有選項

跟蹤一個選項的投票數

我們希望將 Redis 作為我們的資料庫使用。

模型

我們的模型主要就是Question 和 Choice。由於這兩個模型與其他模型都有一些相似的功能,因此我們可以創建一個基類 Model,Question 與 Choice 都繼承自這個基類 Model。

基礎模型

Model 應該是這樣的:

類 Question 如下:

我們來為 Model 的不同方法添加實現。

latest_instance_id_key:

list_key:

add_to_list:

add_to_list 使用了 Redis 中的列表將所有實例的 key 存入 redis。我麼這裡使用 redis-py 中的 lpush 方法,它會映射到 redis 中的 LPUSH 操作。

稍後我們會添加生成 self.id 的代碼。

確保 connection 定義在 models.py 模塊內是可訪問的。

latest_instance_id:

increment_latest_instance_id:

cache_key

save:

注意我們這裡在 save() 方法中用的是 self.repr() 方法。它可以調用子類中定義的 repr() 方法,返回一個我們要保存的屬性的字典。這個稍後解釋。

你需要關注的是 save() 中是怎樣調用 increment_latest_instance_id() 和 add_to_list() 的。

save() 方法還用到了 redis-py 中的 hmset 方法,其對應 redis 中的 HMSET 命令。通過這種方式保存實例中我們需要的屬性。

子類模型

現在我們來實現類 Question。

由於子類的 save 方法使用到了 repr() 方法,所以其每一個子類都要實現 repr() 方法。repr() 應該返回的是我們希望在 redis 中持久化的字典形式的數據。比如我們希望一個問題的 id 以及 question_text 保存在 redis 中,那麼 repr() 返回的字典中應該包含這些屬性。

當我們試著使用 save() 保存第一個實例的時候,其內部會調用 latest_instance_id_key() 方法,期望能從 redis 取出已經存在的鍵 question-latest-id。

我們來創建一個文件 migration 並向 redis 中保存一個鍵。

運行這個文件:


使用 ORM

通過 ipython 運行我們的代碼。

首先確保你的 redis 伺服器 redis-server 已經啟動了。

現在啟動一個 redis 客戶端 redis-cli,然後校驗一下 question-1 是否已經插入到 redis 中了。

這裡同樣還校驗了 questions 的存在。再來看看 id 有沒有保存到 questions 中。

現在再來校驗一下 id 和 question_text 是否也被保存在 questions 中。

我們再來用 ipython 創建一個 question 並將其保存在 redis 中。

現在看看我們期望的鍵值是否都保存到 redis 中了。


提取問題

我們添加一個 Question 方法來根據給出的 id 提取一個問題。

注意這裡我們傳入了 id 作為 cache_key。相應地我們就需要修改 cache_key 的代碼:

現在來使用之前添加的 questions 的 ids 來提取它們。

不過需要確保 save 功能可用。

非常棒!

提取所有問題

我們再添加一個方法來提取所有問題。

現在使用這個方法提取問題。

get_question 和 get_questions 擁有相似的功能並且可以使用我們稍後添加的模型。所以,現在將它們移到基類中去。將 get_question 重命名為 get,將 get_questions 重命名為 list。

現在就類用一下 get() 和 list() 方法,並校驗一下其功能是否符合預期。


其他子類模型

現在來添加一個 Choice 模型。

在保存 choice 模型之前,我們需要添加一個鍵 choice-latest-id。還記得我們之前的 migrations.py 文件嗎?

在 ipython 中執行。

現在我們通過 Choice 來演示 ORM 操作。

這應該歸功於我們的基類。通過 Choice 我們可以自由地使用 save(),get(),list() 等方法。

英文原文:https://www.agiliq.com/blog/2019/11/writing-an-orm-for-redis/ 
譯者:居老師的龍尾巴

相關焦點

  • Python操作Redis
    'name', 'phyger-from-python-redis')  # key是"name" value是"phyger-from-python-redis" 將鍵值對存入redis緩存print(r['name'])  # 第一種:取出鍵name對應的值print(r.get('name'))  # 第二種:取出鍵name對應的值print(type(r.get('name
  • REDIS 如何利用python 操作redis 集群 (投稿文章)
    ## 利用python操作redis集群redis的cluster模式為大型應用中常用的方式,今天學習如何使用redis-py-cluster來操作redis集群首先安裝redis-py-cluster```pip install redis-py-cluster```基本用法``
  • Python操作Redis大全
    模塊對字符串(string)的主要操作函數包括:SET、GET、GETSET、SETEX、SETNX、MSET、MSETNX、INCR(INCRBY,DECR,DECRBY在python中庸同一個函數incr實現)、APPEND、SETRANGE、STRLEN。
  • 315道Python面試題,歡迎挑戰!
    11、python遞歸的最大層數?(水平、垂直)25、redis和memcached比較?26、redis中資料庫默認是多少個db 及作用?27、python操作redis的模塊?28、如果redis中的某個列表中的數據量非常大,如果實現循環顯示每一個值?29、redis如何實現主從複製?以及數據同步機制?
  • Python | Python學習之Redis交互詳解
    前言最近在學習scrapy redis,順便複習了redis。本篇為redis篇,包含實例演示,主從服務配置,python交互等內容。rpush xianyu 1 2 3 4 5 6在指定元素前或後插入數據:linsert key before/after 現有元素 新元素舉個慄子:linsert xianyu before 1 a獲取列表元素獲取列表指定範圍內的值:lrange key start stop注意:這裡的列表和python
  • 【附答案】300+ 道 2020年 Python面試題 分享
    11、python遞歸的最大層數?(水平、垂直)25、redis和memcached比較?26、redis中資料庫默認是多少個db 及作用?27、python操作redis的模塊?28、如果redis中的某個列表中的數據量非常大,如果實現循環顯示每一個值?29、redis如何實現主從複製?以及數據同步機制?30、redis中的sentinel的作用?
  • 不吹不擂,你想要的Python面試都在這裡了【315+道題】
    11、python遞歸的最大層數?(水平、垂直)25、redis和memcached比較?26、redis中資料庫默認是多少個db 及作用?27、python操作redis的模塊?28、如果redis中的某個列表中的數據量非常大,如果實現循環顯示每一個值?29、redis如何實現主從複製?以及數據同步機制?
  • Redis精進:List的使用和應用場景
    >"python"> lpop books"java"> lpop books"golang"> lpop books(nil)右邊進右邊出:棧# 入棧> rpush books python java golang(integer)
  • Python的輕量級ORM框架peewee
    當然python庫中這類框架非常多,我們並沒有必要自己去實現。ORM框架使用最廣泛的就是SQLAlchemy和Django自帶的ORM框架,但是SQLAlchemy的語法顯然相對Django的ORM框架麻煩一點。
  • Python資料庫ORM工具sqlalchemy的學習筆記
    3. session connection是一般使用資料庫的方式,sqlalchemy還提供了另一種操作資料庫的方式,通過session對象,session可以記錄和跟蹤數據的改變,在適當的時候提交,並且支持強大的ORM的功能,下面是基本使用 from sqlalchemy import create_engine from sqlalchemy.orm
  • redis zset實現排行榜
    轉載自 https://duyanghao.github.io/redis-rank/
  • 如何實現redis主從複製?
    主從複製,主要優勢在於實現了數據備份(主機和從機數據同步一致)、讀寫分離(主機主要負責寫入數據,從機讀數據,在讀大於寫的項目中提高了性能)。最後也為後續集成哨兵機制和集群的實現提供了依據。#主master的redis密碼masterauth 123456第三步:啟動服務,測試配置是否正確啟動三臺伺服器上redis服務。向主機(192.168.1.6) 添加數據,連接Redis#redis沒有設置密碼./redis-cli#redis 設置密碼.
  • 已有資料庫情況下使用Python進行ORM操作
    現狀在實際測試中發現,需要插入大量的測試數據或者有依賴關係的數據 來達到測試的目的,這時我們可以使用python來簡化和規範化該操作。採用 peewee 來將SQL代碼轉化為Python代碼實現ORMpeewee 是一個輕量級的 python ORM 庫。
  • Redis實現分布式阻塞隊列
    Redis分布式鎖實現原理分布式鎖本質上要實現的目標就是在 Redis 裡面佔一個「茅坑」,當別的進程也要來佔時,發現已經有人蹲在那裡了,就只好放棄或者稍後再試。佔坑一般是使用 setnx(set if not exists) 指令,只允許被一個客戶端佔坑。先來先佔, 用完了,再調用 del 指令釋放茅坑。
  • Redis如何實現分布式鎖?
    一般來說,實現分布式鎖的方式有以下幾種:本篇文章主要講解Redis的實現方式。實現思路Redis實現分布式鎖主要利用Redis的setnx命令。setnx是SET if not exists(如果不存在,則 SET)的簡寫。
  • Redlock:Redis分布式鎖最牛逼的實現
    普通實現說道Redis分布式鎖大部分人都會想到:setnx+lua,或者知道set key value px milliseconds nx。後一種方式的核心實現命令如下:- 獲取鎖(unique_value可以是UUID等)SET resource_name unique_value NX PX 30000- 釋放鎖(lua腳本中,一定要比較value,防止誤解鎖)if redis.call("get",KEYS[1]) == ARGV[1] then    return redis.call
  • SQLAlchemy 1.3.8 發布,Python ORM 框架
    orm[orm] [bug] 修復了由於內部上下文字典中的映射器/關係狀態導致 Load 對象不可拾取的錯誤[orm] [usecase
  • Redisson實現Redis分布式鎖的N種姿勢
    如下:Config config = new Config();config.useClusterServers().addNodeAddress(        "redis://172.29.3.245:6375","redis://172.29.3.245:6376", "redis://172.29.3.245:6377",        "redis
  • Redis的LRU算法實現
    所謂刪除策略:當redis使用已經達到了最大內存,比如4GB時,如果這時候再往redis裡面添加新的Key,那麼Redis將選擇一個Key刪除。那如何選擇合適的Key刪除呢?注意:我這裡加了引號,其實在redis的具體實現中,要統計所有的Key的最近訪問時間代價是很大的。想想,如何做到呢?evict keys by trying to remove the less recently used (LRU) keys first, in order to make space for the new data added.
  • Python使用redis存儲對象
    Python總的對象存儲到redis中默認為字符串,那麼如何存儲對象呢?下面就看看如何直接將Python中對象存儲到redis中先寫個測試redis是否正常連接上import rediscache = redis.StrictRedis('172.20.0.227',6379)