建模谷歌数据存储区/ python

时间:2010-10-22 10:14:09

标签: python google-app-engine google-cloud-datastore

您好我正在尝试构建一个类似下面的模型的应用程序:-(虽然很容易将两个模型合并为一个并使用它们,但这在实际的应用程序中是不可行的)< / p>

class User(db.Model):
     username=db.StringProperty()
     email=db.StringProperty()

class UserLikes(db.Model):
      username=db.StringProperty()
      food=db.StringProperty()

目标 - 登录后的用户输入他喜欢的食物,然后应用程序返回所有喜欢该食物的其他用户。 现在假设用户Alice输入她喜欢的“Pizzas”,它会存储在数据存储区中。她退出并再次登录。此时,我们向数据存储区查询她喜欢的食物,然后再次查询所有喜欢该食物的用户。如您所见,这是两个数据存储查询,这不是最好的方法。我相信肯定会有更好的方法来做到这一点。有人可以帮忙。

[更新: - 或者可以做这样的事情,我改变第二个模型,使用户名成为一个多值属性,其中所有喜欢这些食物的用户都可以存储..但是我在这里有点不清楚] < / p>

[编辑:-Hi感谢您的回复,但我发现这两个解决方案在这里有点过分。我试着像下面这样做。请你看看这个和善意的建议。我维护了相同的两个表,但是如下所示进行了更改: -

class User(db.Model):
    username=db.StringProperty()
    email=db.StringProperty()

class UserLikes(db.Model):
     username=db.ListProperty(basestring)
     food=db.StringProperty()

现在当2个用户更新他们喜欢的相同食物时,它会像

一样存储

'pizza'----&gt; '爱丽丝', '鲍勃'

我在这里检索数据的db查询变得非常容易

query=db.Query(UserLikes).filter('username =','Alice').get()

然后我可以像

那样迭代
    for elem in query.username:
          print elem

现在如果有两种食物如下: -

'pizza' ----> 'Alice','Bob'
'bacon'----->'Alice','Fred'

我使用与上面相同的查询,并迭代查询,然后迭代用户名。

我对此很新,意识到这可能是错的。请建议!

2 个答案:

答案 0 :(得分:2)

除了您拥有的关系模型之外,您还可以通过其他两种方式处理此问题,具体取决于您的确切用例。您在更新中有一个好主意,使用ListProperty。查看Brett Slatkin在Relation Indexes上的taslk的某些背景。

您可以在包含食物清单的用户上使用子实体(关系索引):

class UserLikes(db.Model):
    food = db.StringListProperty()

然后,当您创建UserLikes实例时,您将定义与其相关的用户作为父实例:

likes = UserLikes(parent=user)

这使您可以很好地查询喜欢特定食物的其他用户:

like_apples_keys = UserLikes.all(keys_only=True).filter(food='apples')
user_keys = [key.parent() for key in like_apples_keys]
users_who_like_apples = db.get(user_keys)

然而,更适合你的应用的是将关系变成食物的孩子:

class WhoLikes(db.Model):
    users = db.StringListProperty()

创建类似时,将key_name设置为食物名称:

food_i_like = WhoLikes(key_name='apples')

现在,让所有喜欢苹果的用户:

apple_lover_key_names = WhoLikes.get_by_key_name('apples')
apple_lovers = UserModel.get_by_key_names(apple_lover_key_names.users)

让所有喜欢与用户相同的用户:

same_likes = WhoLikes.all().filter('users', current_user_key_name)
like_the_same_keys = set()
for keys in same_likes:
   like_the_same_keys.union(keys.users)
same_like_users = UserModel.get_by_key_names(like_the_same_keys)

如果你有很多喜欢,或者有很多相同喜欢的用户,你需要对这个过程进行一些调整。您将无法获取1,000个用户。

答案 1 :(得分:1)

食物和用户关系是一个所谓的Many-to-Many relationship,通过连接表进行简单处理;在这种情况下,链接用户和食物的db.Model。 像这样:

class User(db.Model):
  name = db.StringProperty()

  def get_food_I_like(self):
     return (entity.name for entity in self.foods)

class Food(db.Model):
  name = db.StringProperty()

  def get_users_who_like_me(self):
    return (entity.name for entity in self.users)

class UserFood(db.Model):
  user= db.ReferenceProperty(User, collection_name='foods')
  food = db.ReferenceProperty(Food, collection_name='users')

对于给定用户的实体,您可以通过以下方式检索首选食物:

userXXX.get_food_I_like()

对于给定食物的实体,您可以通过以下方式检索喜欢该食物的用户:

foodYYY.get_users_who_like_me()

还有另一种方法可以处理在db.ListProperty()内存储密钥列表的多对多关系。

class Food(db.Model):
  name = db.StringProperty()

class User(db.Model):
  name = db.StringProperty()
  food = db.ListProperty(db.Key)

请记住,ListProperty限制为5.000键或再次,您无法添加完全适合连接表的有用属性(例如:表示用户喜欢食物的数量的星数)。