最近我们的应用程序发生了一些数据结构变化,我们决定使用命名空间来分隔不同版本的数据,并使用 mapreduce 任务将旧实体转换为新格式。
现在一切都很好,但我们不想总是孤立我们拥有的整个数据集。我们数据的大部分存储在一种非常简单且不需要经常更改的类型中。所以我们决定使用每个种类的命名空间。
类似于:
class Author(ndb.model.Model):
ns = '2'
class Book(ndb.model.Model):
ns = '1'
因此,当迁移到版本 2 时,我们不需要转换所有数据(并将所有“书籍”类型复制到其他 namespace ),只需转换“作者”类型的实体。然后,我们不定义 appengine_config.namespace_manager_default_namespace_for_request
,而是将“namespace”关键字参数添加到我们的查询中:
Author.query(namespace=Author.ns).get()
问题如何使用这些不同的命名空间来存储(即put()
)不同的种类?像这样的东西:
# Not an API
Author().put(namespace=Author.ns)
当然,以上是行不通的。 (是的,我可以向数据存储区询问该命名空间中的可用 key ,然后使用该 key 来存储实例,但这是我想避免的额外 API 调用。)
最佳答案
为了解决这样的问题我写了一个装饰器如下:
MY_NS = 'abc'
def in_my_namespace(fn):
"""Decorator: Run the given function in the MY_NS namespace"""
from google.appengine.api import namespace_manager
@functools.wraps(fn)
def wrapper(*args, **kwargs):
orig_ns = namespace_manager.get_namespace()
namespace_manager.set_namespace(MY_NS)
try:
res = fn(*args, **kwargs)
finally: # always drop out of the NS on the way up.
namespace_manager.set_namespace(orig_ns)
return res
return wrapper
所以我可以简单地写,对于应该出现在一个单独的命名空间中的函数:
@in_my_namespace
def foo():
Author().put() # put into `my` namespace
当然,将其应用于系统以获得您想要的结果有点超出了本文的范围,但我认为它可能会有所帮助。
编辑:使用 with
上下文
以下是使用 with
上下文完成上述操作的方法:
class namespace_of(object):
def __init__(self, namespace):
self.ns = namespace
def __enter__(self):
self.orig_ns = namespace_manager.get_namespace()
namespace_manager.set_namespace(self.ns)
def __exit__(self, type, value, traceback):
namespace_manager.set_namespace(self.orig_ns)
然后在别处:
with namespace_of("Hello World"):
Author().put() # put into the `Hello World` namespace
关于google-app-engine - App Engine 多个命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9296303/