App Engine多个名称空间

Att*_* O. 3 google-app-engine google-cloud-datastore

最近我们的应用程序中发生了一些数据结构更改,我们决定使用命名空间来分隔不同版本的数据,并使用mapreduce任务将旧实体转换为新格式.

现在一切都很好,但我们不想总是隔离我们拥有的整个数据集.我们数据的最大部分存储在一种非常简单且不需要经常更改的类型中.所以我们决定使用per-kind命名空间.

就像是:

class Author(ndb.model.Model):
    ns = '2'

class Book(ndb.model.Model):
    ns = '1'
Run Code Online (Sandbox Code Playgroud)

因此,在迁移到版本2时,我们不需要转换所有数据(并将所有'Book'类型复制到另一个命名空间),只需要'Author'类型的实体.然后,appengine_config.namespace_manager_default_namespace_for_request我们只是查询的'namespace'关键字参数,而不是定义它:

Author.query(namespace=Author.ns).get()
Run Code Online (Sandbox Code Playgroud)

问题:如何put()使用这些不同的命名空间存储(即)不同种类?就像是:

# Not an API
Author().put(namespace=Author.ns)
Run Code Online (Sandbox Code Playgroud)

当然,上述方法不起作用.(是的,我可以向数据存储区询问该命名空间中的可用密钥,然后使用该密钥来存储实例,但这是我想要避免的额外API调用.)

Bri*_*unt 5

为了解决这样的问题,我写了一个装饰器如下:

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
Run Code Online (Sandbox Code Playgroud)

所以我可以简单地写一下应该在一个单独的命名空间中发生的函数:

@in_my_namespace
def foo():
   Author().put() # put into `my` namespace
Run Code Online (Sandbox Code Playgroud)

当然,将其应用于系统以获得您想要的结果有点超出了这个范围,但我认为它可能会有所帮助.

编辑:使用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)
Run Code Online (Sandbox Code Playgroud)

其他地方:

with namespace_of("Hello World"):
    Author().put() # put into the `Hello World` namespace
Run Code Online (Sandbox Code Playgroud)