How to structure the movie database and user options?

I would like to create a database of films where the user will be able to mark films that he watched and liked:

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

Will this work? I am using google accounts. How can I choose all the films I like later?


Upd . I stuck with the systempuntoout method and used the following code to save custom options:

 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') 

But if the user makes his choice several times, then several entries are added to the data warehouse ... Wouldn’t it be better to save the user ID and movie ID as a name?

 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 

However, with this approach, if I do not pass liked , it overwrites its value with None (the same with watched , if not passed, None used).

+3
source share
2 answers

I would go with two different models, which stores all the Movies details and one for storing 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() 

If you need to store user information, you must create your UserInfo model, using user_id , from the user API , with all the details of the properties of your application.

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

To create a new UserInfo , you can do:

 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() 

Then, when the user is logged in, use his / t user_id to get watched / favorite movies.

 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()) 
+8
source

You seem to be trying to model many-to-many relationships. There are several ways to model these relationships (see the Many-to-Many section). See also Nick's blog . (Unfortunately, none of these links are written for NDB, so, for example, you cannot use collection_name , that is, backlinks . It is useful to show you how to split the data into different models.)

Here is one way to do this using "join tables" / "models models":

 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() 

Depending on how many users your application will support and how often the database will be updated, it may be more efficient to use duplicate properties (e.g. user lists) instead of connection tables:

 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]) 

Note that I used the predictive query above so that users_who_watched lists are not returned with query results. You probably don't need these, and this should make the extraction much faster.

If you expect, say, less than 1,000 users to watch or like a particular movie, a list approach might be better.

For a more advanced technique, see Creating Scalable Complex Applications in App Engine , where Bret shows how to move a repeat / list property into a separate model using parent keys.

+3
source

All Articles