如何创建匹配键的查询?

时间:2012-01-07 00:13:59

标签: google-app-engine google-cloud-datastore reference python-2.7 webapp2

我使用另一个用户(赞助商)的密钥来指示谁是用户的赞助商,并在数据存储区中为拥有赞助商的用户创建一个链接,最多只有一个,但赞助商可以赞助许多用户喜欢在这种情况下ID 2002赞助其他三个用户:

enter image description here

在这种情况下,此查询执行我想要的操作:SELECT * FROM User where sponsor =KEY('agtzfmJuYW5vLXd3d3ILCxIEVXNlchjSDww')但我不知道如何使用python编程,我只能将它用于数据存储区。当我想匹配在同一字段中具有相同用户密钥的用户集时,如何通过密钥进行查询?我的模型中的用户最多只能有一个赞助商,我只想知道某个人赞助的用户列表,然后他们轮流赞助用户,我也想查询。

现场赞助商是一个密钥,它有一个指向数据存储区中赞助商的链接。我设置密钥就像user2.sponsor = user1.key一样,现在我想找到所有user1赞助的查询应该就像

User.All().filter('sponsor = ', user1.key)

但赞助商是类型键的字段,所以我不知道如何匹配它以查看例如活跃用户是赞助商的人的列表以及当第二代也有链接时它如何成为树。如何选择此用户为赞助商的用户列表,然后选择第二代用户?当我建模关系时,简单地说就像u1 = u2.key,即user2.sponsor = user1.key。谢谢你的提示

以下解决方法是不好的做法,但这是我最后也唯一的选择:

def get(self):
    auser = self.auth.get_user_by_session()
    realuser = auth_models.User.get_by_id(long( auser['user_id'] ))
    q = auth_models.User.query()
    people = []
    for p in q:
      try:
        if p.sponsor == realuser.key:
           people.append(p)
      except Exception, e:
        pass
    if auser: 
        self.render_jinja('my_organization.html', people=people, user=realuser,)

更新

问题是keyproperty不是必需的,并且当我认为这是我的代码中的错误时,Guido Van Rossum已将此报告为ndb中的错误。以下是我现在正在使用的内容,这是一个非常可接受的解决方案,因为除了可能的程序员,测试人员和管理员之外,组织中的每个真实用户都需要拥有一个用户ID的赞助商ID。

from ndb import query
class Myorg(NewBaseHandler):
    @user_required
    def get(self):
        user = auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id']))
    people = auth_models.User.query(auth_models.User.sponsor == user.key).fetch()
        self.render_jinja('my_organization.html', people=people,
                              user=user) 

class User(model.Expando):
    """Stores user authentication credentials or authorization ids."""

    #: The model used to ensure uniqueness.
    unique_model = Unique
    #: The model used to store tokens.
    token_model = UserToken
    sponsor = KeyProperty()
    created = model.DateTimeProperty(auto_now_add=True)
    updated = model.DateTimeProperty(auto_now=True)
    # ID for third party authentication, e.g. 'google:username'. UNIQUE.
    auth_ids = model.StringProperty(repeated=True)
    # Hashed password. Not required because third party authentication
    # doesn't use password.
    password = model.StringProperty()
    ...

2 个答案:

答案 0 :(得分:5)

User模型是一个NDB Expando,查询起来有点棘手。

来自docs

  

另一个有用的技巧是查询动态的Expando类型   属性。您将无法使用class.query(class.propname ==   value)因为类没有属性对象。相反,你可以   使用ndb.query.FilterNode类构造过滤器表达式,   如下:

from ndb import model, query

class X(model.Expando):
  @classmethod
  def query_for(cls, name, value):
    return cls.query(query.FilterNode(name, '=', value))

print X.query_for('blah', 42).fetch()

所以试试:

form ndb import query

def get(self):
    auser = self.auth.get_user_by_session()
    realuser = auth_models.User.get_by_id(long( auser['user_id'] ))
    people = auth_models.User.query(query.FilterNode('sponsor', '=', realuser.key)).fetch()
    if auser: 
        self.render_jinja('my_organization.html', people=people, user=realuser,)

答案 1 :(得分:2)

选项#2

这个选项有点清洁。您将模型子类化并将其位置传递给webapp2。这将允许您向类添加自定义属性和自定义查询。

# custom_models.py
from webapp2_extras.appengine.auth.models import User
from google.appengine.ext.ndb import model

class CustomUser(User):
    sponsor = model.KeyProperty()

    @classmethod
    def get_by_sponsor_key(cls, sponsor):
        # How you handle this is up to you. You can return a query 
        # object as shown, or you could return the results.
        return cls.query(cls.sponsor == sponsor)

# handlers.py
def get(self):
    auser = self.auth.get_user_by_session()
    realuser = custom_models.CustomUser.get_by_id(long( auser['user_id'] ))
    people = custom_models.CustomUser.get_by_sponsor_key(realuser.key).fetch()
    if auser:
        self.render_jinja('my_organization.html', people=people, user=realuser,)


# main.py
config = {
    # ...
    'webapp2_extras.auth': {
        # Tell webapp2 where it can find your CustomUser
        'user_model': 'custom_models.CustomUser',
    },
}

application = webapp2.WSGIApplication(routes, config=config)