【问题标题】:Google app engine - Python: How to use Namespaces and Ancestors?Google 应用引擎 - Python:如何使用命名空间和祖先?
【发布时间】:2014-12-22 23:44:25
【问题描述】:

我试图了解命名空间和祖先在 GAE 中的工作方式。 所以我制作了一个简单的多租户“ToDo List”应用程序,其中每个租户都是一个用户。所以我在 appengine_config.py 中设置命名空间,如下所示:

def namespace_manager_default_namespace_for_request():
    name = users.GetCurrentUser().user_id()
return name

然后在我的 ma​​in.py 中管理视图,如下所示:

#Make tasks with strong consistency by giving them a parent
DEFAULT_TASKS_ANCESTOR = ndb.Key('Agenda', 'default_agenda')


class TasksList(webapp2.RequestHandler):
def get(self):
    namespace = namespace_manager.get_namespace()
    tasks_query = Task.query(ancestor=DEFAULT_TASKS_ANCESTOR)
    tasks = tasks_query.fetch(10, use_cache=False)
    context = {
        'tasks': tasks,
        'namespace': namespace,
    }
    template = JINJA_ENVIRONMENT.get_template('templates/tasks_list.html')
    self.response.write(template.render(context))

def post(self):
    name = cgi.escape(self.request.get('name'))
    task = Task(parent=DEFAULT_TASKS_ANCESTOR)
    task.name = name
    task.put()
    self.redirect('/tasks_list')

...这给出了泄漏的数据:

  1. 我以 userA 的身份登录,创建了一个任务,然后注销并以另一个用户 (userB) 的身份再次登录,我可以从 userA 看到该任务。 我从管理面板确认任务实体来自不同的命名空间,并且祖先也不同,“因为它包含命名空间?”。

  2. 我还使用.fetch(10, use_cache=False) 关闭了缓存。但问题仍然存在。所以这不是缓存问题。

  3. 所以最后我在.query().put() 之前创建了父级,它确实有效!像这样: DEFAULT_TASKS_ANCESTOR = ndb.Key('Agenda', 'default_agenda') tasks_query = Task.query(ancestor=DEFAULT_TASKS_ANCESTOR)

但现在我有问题......

  1. 为什么有效?由于这些任务实体不共享相同的命名空间,我如何从另一个命名空间查询数据?即使我错误地从另一个命名空间查询祖先,我应该获取数据吗?

  2. 来自 namespaceADEFAULT_TASKS_ANCESTOR 是否与来自 namespaceBDEFAULT_TASKS_ANCESTOR 相同,或者它们是两个完全不同的祖先?

  3. 命名空间是否真的对数据存储区中的数据进行了划分,或者事实并非如此?

  4. 如果祖先即使在命名空间中也扮演着如此重要的角色,我是否仍应使用命名空间或祖先来划分多租户应用程序中的数据?

提前谢谢你!

【问题讨论】:

    标签: python google-app-engine namespaces multi-tenant


    【解决方案1】:

    我认为您的问题是在请求之外定义 DEFAULT_TASKS_ANCESTOR 常量。在这种情况下,数据存储使用默认命名空间来创建此密钥。因此,通过使用该祖先键进行查询,您使用了相同的命名空间。

    来自谷歌的数据存储documentation

    默认情况下,数据存储使用命名空间管理器中的当前命名空间设置来处理数据存储请求。 API 在创建时将此当前命名空间应用于 Key 或 Query 对象。因此,如果应用程序以序列化形式存储 Key 或 Query 对象,则需要小心,因为命名空间保留在这些序列化中。

    正如您所发现的,当您在请求中定义祖先键时,它就起作用了。您可以在构造函数调用中为特定查询设置命名空间(即ndb.Query(namespace='1234')),这样您就可以从不同的命名空间查询实体。

    关于您的其他问题:

    1. 据我了解,这些是不同的键,因为它们包含不同的命名空间。
    2. 要进行硬划分,您可以在服务器端检查用于查询的命名空间是否等于当前用户的用户 ID。
    3. 这实际上取决于应用程序的整体结构。恕我直言,祖先键与强一致性更相关。想想用户可能有多个待办事项列表的情况。他应该能够看到所有这些,但可能仅在列表级别需要高度一致性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多