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

Python 如何在App Engine中表示一对一关系,python,google-app-engine,bigtable,schema-design,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.Strin

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

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中为用户设置ReferenceProperty,但这实际上是一对多,因为每个用户都有多个UserTwitterOauth对象。您希望最多有一个UserTwitterOauth与任何用户相关。如何在一对一的基础上关联这些模型?

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

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

编辑防止多个访问令牌引用同一用户:

您可以通过
User.usertwitteroauth\u set
属性作为查询访问引用访问令牌。如果需要更具描述性的名称,请在设置ReferenceProperty时指定参数
collection\u 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')

在这种特定情况下,最好的选择可能是将
usertwitterouth
实体设置为
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
类添加一个简单的方法或属性,以便于检索附加信息;向
usertwitterouth
添加一个类方法,以用作工厂方法,保留约定


顺便说一句,请注意,
User
对于实体来说是一个危险的名称-Users API也有一个名为
User
的类,除非您非常小心导入,当您打算引用另一个模型时,您可能会引用其中一个。

作为旁白:不要因为您认为模型更有效而拆分模型。从长远来看,将所有内容都保存在一个实体上会更加有效,从而节省了多次昂贵的api调用,特别是在您发布的示例中。当您的用户模型上有数百个属性时,回来问这个问题,只有这样才能提高写入性能;-)@克里斯:本质上,这个问题可能是关于过早优化的。但就个人而言,我喜欢将用户工件与其潜在连接分离的想法。如果你想在twitter连接之外建立一个linkedin连接的模型怎么办。。。依此类推。@jon,使用GAE的很大一部分工作倾向于寻找使数据模型非标准化的方法,以使您能够轻松地查询数据模型并减少API调用,对于这种特殊情况,这似乎是不必要的,即使有20个不同的连接。所以你要设置的是,进行较少的api调用通常比进行较小的api调用更好?@ʞɔıu作为一个泛化,是的,但这在很大程度上取决于实体的大小及其属性的数量。截止值远高于您在这里处理的几个额外属性。另外,虽然你的用户名很有趣,但在回复中很难引用你。我能以某种方式防止被复制者使用事务吗?请注意,使用db.put([my_user,extra_info])可能更有效,不?@sahid只有在为
用户
实体使用密钥名时才可能。