这是我的问题:
class City(Model):
name = StringProperty()
class Author(Model):
name = StringProperty()
city = ReferenceProperty(City)
class Post(Model):
author = ReferenceProperty(Author)
content = StringProperty()
代码并不重要......它的django模板:
{% for post in posts %}
<div>{{post.content}}</div>
<div>by {{post.author.name}} from {{post.author.city.name}}</div>
{% endfor %}
现在假设我使用Post.all().fetch(limit=100)
获得前100个帖子,并将此列表传递给模板 - 会发生什么?
它使得 200更多数据存储区得到 - 每个作者获得100个,获得每个作者城市100个。
实际上,这是完全可以理解的,因为帖子只提到了作者,而作者只提到了这个城市。 __get__
和post.author
对象上的author.city
访问者透明地获取并提取数据(请参阅this问题)。
围绕这个的一些方法是
Post.author.get_value_for_datastore(post)
收集作者密钥(请参阅上面的链接),然后批量获取以获取所有密钥 - 这里的麻烦是我们需要重新构建模板数据对象...需要为每个模型和处理程序提供额外代码和维护的东西。 cached_author
,首先检查作者的memcache并返回 - 这里的问题是post.cached_author将被调用100次,这可能意味着100个memcache调用。 cached_author
访问者可以参考此地图。 所有这些想法都需要额外的代码和维护,而且它们不是很透明。如果我们能做什么
@prefetch
def render_template(path, data)
template.render(path, data)
原来我们可以...... hooks和Guido's instrumentation module都证明了这一点。如果@prefetch
方法通过捕获请求的键来包装模板渲染,我们可以(至少一个深度级别)捕获正在请求的键,返回模拟对象,并批量访问它们。这可以针对所有深度级别重复,直到没有请求新密钥。最终渲染可以拦截获取并从地图返回对象。
这会将 200 的总数变为 3 ,透明且无需任何额外代码。更不用说在无法使用memcache的情况下大大减少了对memcache的需求和帮助。
麻烦是我不知道怎么做(还)。在我开始尝试之前,还有其他人这样做过吗?或者有人想帮忙吗?或者您是否看到计划中存在严重缺陷?
答案 0 :(得分:1)
我一直处于类似情况。我没有ReferenceProperty,而是有父/子关系,但基础是相同的。我当前的解决方案并没有得到完善,但至少它足以用于报告和200-1,000个实体的事物,每个实体都有几个需要提取的子实体。
您可以批量手动搜索数据并根据需要进行设置。
# Given the posts, fetches all the data the template will need
# with just 2 key-only loads from the datastore.
posts = get_the_posts()
author_keys = [Post.author.get_value_for_datastore(x) for x in posts]
authors = db.get(author_keys)
city_keys = [Author.city.get_value_for_datastore(x) for x in authors]
cities = db.get(city_keys)
for post, author, city in zip(posts, authors, cities):
post.author = author
author.city = city
现在,当您渲染模板时,不会进行任何其他查询或提取。它的边缘很粗糙,但如果没有我刚才描述的这种模式,我就无法生存。
此外,您可能会考虑验证您的实体都不是None
,因为如果密钥错误,db.get()将返回None。这只是进入基本数据验证。同样,如果存在超时等,则需要重试db.get()。
(最后,我认为memcache不会作为主要解决方案。可能作为加速数据存储调用的辅助层,但如果memcache为空,则需要运行良好。此外,Memcache本身有几个配额,如memcache调用和传输的总数据。过度使用memcache是一种很好的方法来杀死你的应用程序。)
答案 1 :(得分:0)
以下是预取的一些很好的例子......
http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine