首页 > 解决方案 > 带有 API 调用的 Django LRU_Cache

问题描述

我正在尝试通过 PRAW ( https://praw.readthedocs.io/en/stable/ ) 将 Reddit API 与 Django 一起使用,并且正在考虑尝试使用 functoolslru_cache装饰器来实现某种缓存,以便我可以缓存类似 API 调用的结果,以减少进行的总体调用。我从来没有做过这样的事情,所以我一直主要关注实现@lru_cache装饰器的示例。

我有 3 个文件主要涉及 API 调用/显示在这里。我有:

account.html

{% extends 'myapp/base.html' %}
<h1> {{ name }} </h1>
<h3> {{ comment_karma }} </h3>

<h5> Top Posts </h5>
<table>
    <tr>
        <th> Post </th>
        <th> Subreddit </th>
    </tr>
    {% for s in top_submissions %}
        <tr>
           <td> {{ s.title }} </td>
            <td> {{ s.subreddit }} </td>
        </tr>
    {% endfor %}
</table>

视图.py

from . import reddit

reddit = reddit.Reddit()

def account_page():
    context = reddit.details(request.user.reddit_username)
    return render(request, 'stats/dashboard.html', context)

reddit.py

 from functools import lru_cache

 class Reddit:
    def __init__(self):
        self.praw = praw.Reddit(
            client_id = CLIENT_ID,
            client_secret = CLIENT_SECRET,
            user_agent = USER_AGENT
        )

     @lru_cache(maxsize = 256)
     def details(self, redditor):
        redditor = self.praw.redditor(redditor)

        overview = {
            'name': redditor.name,
            'comment_karma': redditor.comment_karma,
            'top_submissions': redditor.submissions.top(limit=10),
        }
        return overview

问题是:当我没有 lru_cache 时,一切正常,所有数据都像往常一样进入。但是,当我确实放置了 lru_cache 选项时,只有 name 和 comment_karma 出现,而​​提交(一个可迭代的列表)只是没有显示在我的页面上(所以我假设它最终没有任何值)。

我使用 lru_cache 错了吗?本质上,我的目标是如果将 aredditor传递给 function overview,我不想一遍又一遍地进行相同的 API 调用,而是希望将其放入缓存中,如果它在缓存中,则提取相同的数据。

标签: pythonpython-3.xdjango

解决方案


PRAW 返回延迟评估的生成器对象。您想在缓存函数中评估它们。否则,生成器耗尽后,您将无法再次获得结果。

所以工作版本应该是这样的:

     @lru_cache(maxsize = 256)
     def details(self, redditor):
        redditor = self.praw.redditor(redditor)

        overview = {
            'name': redditor.name,
            'comment_karma': redditor.comment_karma,
            'top_submissions': list(redditor.submissions.top(limit=10)),
        }
        return overview

list(redditor.submissions.top(limit=10))将消耗生成器,缓存结果将包含列表,而不是只能消耗一次的生成器对象。


推荐阅读