如何构建电影数据库和用户选择?

时间:2012-07-29 16:53:13

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

我想创建电影数据库,用户可以在其中标记他/她观看和喜欢的电影:

class Movies(ndb.Model):
    watched = ndb.UserProperty()
    liked = ndb.UserProperty()

那会有用吗?我使用Google帐户。 我应该如何选择以后所有用户喜欢的电影?


UPD 即可。我已关注systempuntoout approach并使用以下代码保存用户选择:

user = users.get_current_user()
if user:
    userschoices = models.UsersChoices(
        movie=ndb.Key(models.Movies, movie_id), # TODO: what if movie_id is wrong?
        watched=True,
        user_id=user.user_id()
        )
    try:
        userschoices.put()
        self.response.out.write('1')
    except:
        self.response.out.write('0')

但是如果用户多次做出选择,那么会向数据存储区添加几条记录...... 将用户ID和电影ID保存为keyname会不会更好?

userschoices = models.UsersChoices.get_by_id(user.user_id() + '-' + movie_id)
if userschoices is None:
    userschoices = models.UsersChoices(id=user.user_id() + '-' + movie_id)
userschoices.movie = ndb.Key(models.Movies, movie_id) # TODO: what if movie_id is wrong?
userschoices.user_id = user.user_id()
if option == 'liked':
    userschoices.liked = True
elif option == 'watched':
    userschoices.watched = True

但是,如果我没有通过liked这样做,那么它会用None覆盖其值(与watched相同,如果没有通过,{{1使用)。

2 个答案:

答案 0 :(得分:8)

我会使用两种不同的模型,一种存储所有Movies个详细信息,另一种存储UserChoices

class Movies(ndb.Model):
    title = ndb.StringProperty(required=True)
    director = ndb.StringProperty()
    whatever = ndb.StringProperty()

class UsersChoices(ndb.Model):
    movie = ndb.KeyProperty(kind=Movies, required=True)
    watched = ndb.BooleanProperty(required=True)
    liked = ndb.BooleanProperty(required=True)
    user_id = ndb.StringProperty(required=True)

    @classmethod
    def get_liked_movies(cls, user_id):
        return cls.query(cls.user_id == user_id, cls.liked == true).fetch(10)

    @classmethod
    def get_watched_movies(cls, user_id):
        return cls.query(cls.user_id == user_id, cls.watched == true).fetch(10)

    @classmethod
    def get_by(cls, user_id, movie_key):
        return cls.query(cls.user_id == user_id, cls.movie == movie_key).get()

如果您需要存储有关用户的信息,则应创建UserInfo模型,该模型由users API中的user_id键入,并提供应用所需的所有详细信息。

class UserInfo(ndb.Model):
        #Keyed by user_id 
        nickname = ndb.StringProperty()
        email = ndb.StringProperty()

要创建新的UserInfo,您可以执行以下操作:

from google.appengine.api import users

user = users.get_current_user()
userinfo = UserInfo(
        id = user.user_id(),
        nickname = user.keyname(),
        email = user.email()
      )
userinfo.put()

然后,当用户登录时,使用他/她的user_id来检索观看/喜欢的电影。

from google.appengine.api import users

user = users.get_current_user()
userinfo = ndb.Key(UserInfo, user.user_id()).get()
watched_movies = UsersChoices.get_watched_movies(userinfo.key.id())
liked_movies = UsersChoices.get_liked_movies(userinfo.key.id())

答案 1 :(得分:3)

看起来你正试图模仿多对多关系。 There are a few ways to model this relationship(参见“多对多”部分)。另见Nick's blog。 (不幸的是,这些引用都不是为NDB编写的,例如,you can't use collection_name, i.e., back-references。但它们仍然有助于向您展示如何将数据分解为不同的模型。)

使用“连接表”/“关系模型”,这是你可以做到的一种方式:

class Movie(ndb.Model):
    title = ndb.StringProperty(required=True)

class LikedMovie(ndb.Model):
    movie = ndb.KeyProperty(kind=Movie, required=True)
    user  = ndb.StringProperty(required=True)  # user.user_id()

class WatchedMovie(ndb.Model):
    movie = ndb.KeyProperty(kind=Movie, required=True)
    user  = ndb.StringProperty(required=True)  # user.user_id()

...
    movies_user_likes = LikedMovie.query(LikedMovie.user == user.user_id()).fetch()

根据您的应用程序将支持的用户数量以及数据库更新的频率,使用重复属性(即用户列表)而不是连接表可能更有效:

class Movie(ndb.Model):
    title = ndb.StringProperty(required=True)
    users_who_watched = ndb.StringProperty(repeated=True)  # list of user.user_id()s
    users_who_liked   = ndb.StringProperty(repeated=True)  # list of user.user_id()s

...
    movies_user_likes = Movie.query(Movie.users_who_liked == user.user_id()).fetch(projection=[Movie.title])

请注意,我上面使用了projection query,因此不会返回带有查询结果的users_who_watched列表。你可能不需要这些,这应该可以更快地获取。

如果您希望少于1,000个用户观看或喜欢特定电影,则列表方法可能会更好。

有关更高级的技术,请参阅Building Scalable, Complex Apps on App Engine,其中Brett演示了如何使用父键将重复/列表属性移动到单独的模型中。