Python 实现 Redis ORM

议题

我们来为 Redis 写一个简单而优雅的 ORM。这篇文章的灵感来自于 Django ORM。

这篇文章假定你对 Redis 以及 Python 中的 redis 库 redis-py 有了基本的了解。

实体

假设我们正在开发一个轮询应用程序,这个应用包括 Question 和 Choice。每一个问题都有多个选项。

我们希望在我们的应用程序中具有以下能力:

  • 存储问题列表并检索
  • 根据 id 检索问题
  • 存储选项
  • 关联问题与选项列表
  • 将问题与选项取消关联
  • 检索一个问题的所有选项
  • 跟踪一个选项的投票数

我们希望将 Redis 作为我们的数据库使用。

模型

我们的模型主要就是Question 和 Choice。由于这两个模型与其他模型都有一些相似的功能,因此我们可以创建一个基类 Model,Question 与 Choice 都继承自这个基类 Model。

基础模型

Model 应该是这样的:

Python 实现 Redis ORM

类 Question 如下:
Python 实现 Redis ORM

我们来为 Model 的不同方法添加实现。

latest_instance_id_key:

Python 实现 Redis ORM

list_key:

Python 实现 Redis ORM

add_to_list:

Python 实现 Redis ORM

add_to_list 使用了 Redis 中的列表将所有实例的 key 存入 redis。我么这里使用 redis-py 中的 lpush 方法,它会映射到 redis 中的 LPUSH 操作。

稍后我们会添加生成 self.id 的代码。

确保 connection 定义在 models.py 模块内是可访问的。

Python 实现 Redis ORM

latest_instance_id:

Python 实现 Redis ORM

increment_latest_instance_id:

Python 实现 Redis ORM

cache_key

Python 实现 Redis ORM

save:

Python 实现 Redis ORM

注意我们这里在 save() 方法中用的是 self.repr() 方法。它可以调用子类中定义的 repr() 方法,返回一个我们要保存的属性的字典。这个稍后解释。

你需要关注的是 save() 中是怎样调用 increment_latest_instance_id() 和 add_to_list() 的。

save() 方法还用到了 redis-py 中的 hmset 方法,其对应 redis 中的 HMSET 命令。通过这种方式保存实例中我们需要的属性。

子类模型

现在我们来实现类 Question。

Python 实现 Redis ORM

由于子类的 save 方法使用到了 repr() 方法,所以其每一个子类都要实现 repr() 方法。repr() 应该返回的是我们希望在 redis 中持久化的字典形式的数据。比如我们希望一个问题的 id 以及 question_text 保存在 redis 中,那么 repr() 返回的字典中应该包含这些属性。

当我们试着使用 save() 保存第一个实例的时候,其内部会调用 latest_instance_id_key() 方法,期望能从 redis 取出已经存在的键 question-latest-id。

我们来创建一个文件 migration 并向 redis 中保存一个键。

Python 实现 Redis ORM

运行这个文件:

Python 实现 Redis ORM

使用 ORM

通过 ipython 运行我们的代码。

Python 实现 Redis ORM

首先确保你的 redis 服务器 redis-server 已经启动了。

Python 实现 Redis ORM

现在启动一个 redis 客户端 redis-cli,然后校验一下 question-1 是否已经插入到 redis 中了。

Python 实现 Redis ORM

这里同样还校验了 questions 的存在。再来看看 id 有没有保存到 questions 中。

Python 实现 Redis ORM

现在再来校验一下 id 和 question_text 是否也被保存在 questions 中。

Python 实现 Redis ORM

我们再来用 ipython 创建一个 question 并将其保存在 redis 中。

Python 实现 Redis ORM

现在看看我们期望的键值是否都保存到 redis 中了。

Python 实现 Redis ORM

提取问题

我们添加一个 Question 方法来根据给出的 id 提取一个问题。

Python 实现 Redis ORM

注意这里我们传入了 id 作为 cache_key。相应地我们就需要修改 cache_key 的代码:

Python 实现 Redis ORM

现在来使用之前添加的 questions 的 ids 来提取它们。

Python 实现 Redis ORM

不过需要确保 save 功能可用。

Python 实现 Redis ORM

非常棒!

提取所有问题

我们再添加一个方法来提取所有问题。

Python 实现 Redis ORM

现在使用这个方法提取问题。

Python 实现 Redis ORM

get_question 和 get_questions 拥有相似的功能并且可以使用我们稍后添加的模型。所以,现在将它们移到基类中去。将 get_question 重命名为 get,将 get_questions 重命名为 list。

Python 实现 Redis ORM

现在就类用一下 get() 和 list() 方法,并校验一下其功能是否符合预期。

Python 实现 Redis ORM

其他子类模型

现在来添加一个 Choice 模型。

Python 实现 Redis ORM

在保存 choice 模型之前,我们需要添加一个键 choice-latest-id。还记得我们之前的 migrations.py 文件吗?

在 ipython 中执行。

Python 实现 Redis ORM

现在我们通过 Choice 来演示 ORM 操作。

Python 实现 Redis ORM

这应该归功于我们的基类。通过 Choice 我们可以自由地使用 save(),get(),list() 等方法。

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

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-02-09
  • 2021-06-17
  • 2021-10-19
  • 2021-11-06
  • 2022-02-12
猜你喜欢
  • 2022-12-23
  • 2021-10-14
  • 2021-10-13
  • 2021-12-09
  • 2022-01-07
  • 2022-01-17
  • 2021-09-08
相关资源
相似解决方案