如何在App Engine中表示一对一的关系

时间:2011-06-07 16:22:18

标签: python google-app-engine bigtable schema-design

假设您有一个“用户”记录的概念,您希望将其存储在数据存储中。

class User (db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  created = db.DateTimeProperty(auto_now_add=True)
  twitter_oauth_token = db.StringProperty()
  twitter_oauth_secret = db.StringProperty()

您几乎在使用用户对象时都会使用某些字段,例如first_name和last_name。

但是,有些字段只有一个用例,例如,twitter_oauth_token和twitter_oauth_secret,当95%的时间不需要它们时,打扰序列化和反序列化效率会有些低效。

因此,如果您拆分模型:

class User (db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  created = db.DateTimeProperty(auto_now_add=True)

class UserTwitterOauth(db.Model):
  oauth_token = db.StringProperty(required=True)
  oauth_secret = db.StringProperty(required=True)
  created = db.DateTimeProperty(auto_now_add=True)

你可以在UserTwitterOauth中为User提供一个ReferenceProperty,但这实际上是一对多的,因为没有什么能阻止每个用户使用多个UserTwitterOauth对象。您希望最多只有一个UserTwitterOauth与任何用户相关。你如何一对一地将这些模型联系起来?

2 个答案:

答案 0 :(得分:6)

在这种特定情况下,您最好的选择可能是使UserTwitterOauth实体成为具有众所周知密钥名称的User实体的子实体,如下所示:

my_user = User(first_name="John", last_name="Smith")
my_user.put()
extra_info = UserTwitterOauth(parent=my_user, key_name="UserTwitterOauth")
extra_info.put()

您可以向User类添加简单的方法或属性,以便于检索其他信息,并将UserTwitterOauth的类方法添加为工厂方法,从而保留约定。

顺便提一下,请注意User是实体的危险名称 - 用户API也有一个名为User的类,除非您对导入非常小心,否则最终可能会引用当你打算引用另一个时,你就来了。

答案 1 :(得分:0)

在我看来,从Twitter访问令牌到用户的引用属性是最容易维护的。确实,许多访问令牌都可以引用用户。

然而,在工作GAE时,你会发现自己很多时候会按惯例做事。

EDIT阻止多个访问令牌引用同一用户:

您可以通过User.usertwitteroauth_set属性访问引用访问令牌作为查询。如果需要更具描述性的名称,请在设置ReferenceProperty时指定参数collection_name。比如说你想在添加一个新引用令牌之前删除任何引用访问令牌,你可以这样收集逻辑:

class User(db.Model):
    def set_access_token(self, access_token):
        db.delete(self.twitter_access_tokens) # Think this should work, otherwise iterate over the query.
        new_access_token.user = self
        new_access_token.put()


class UserTwitterOauth(db.Model):
    user = db.ReferenceProperty(User, collection_name = 'twitter_access_tokens')