2017-04-27 40 views
0

我想有一个用户谁可以评价不同的电影。一部电影可以有很多评级;用户可以评价很多电影。我的数据库关系如何。烧瓶sqlalchemy

我认为这将是这样的:

class User(db.Model, UserMixin): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer(), primary_key=True) 
    username = db.Column(db.String(), nullable=True, unique=True) 
    password = db.Column(db.String(), nullable=True) 



    def __init__(self, *args, **kwargs): 
    super(User, self).__init__(*args, **kwargs) 


class Movie(db.Model): 
    __tablename__ = 'movies' 
    id = db.Column(db.Integer(), primary_key=True) 
    title = db.Column(db.String(), nullable=True) 
    release_year = db.Column(db.String(), nullable=True) 
    imdb_url = db.Column(db.String(), nullable=True) 
    poster = db.Column(db.String(), nullable=True) 
    description = db.Column(db.String(), nullable=True) 
    genre = db.Column(db.String(), nullable=True) 
    rating = db.Column(db.String(), nullable=True) 


    def __init__(self, *args, **kwargs): 
     super(Movie, self).__init__(*args, **kwargs) 

class Rating(db.Model): 
    __tablename__ = 'ratings' 
    id = db.Column(db.Integer(), primary_key=True) 
    movie_id = db.Column(db.Integer(), db.ForeignKey('movies.id')) 
    user_id = db.Column(db.Integer(), db.ForeignKey('users.id')) 
    rating = db.Column(db.Float(), default='0') 

    user = db.relationship("User", backref=backref("ratings", order_by=id)) 
    movie = db.relationship("Movie", backref=backref("ratings", order_by=id)) 

如果这是正确的,我将如何查询这些表以获得每个电影的所有用户和他们的收视率,然后生成一个大熊猫数据框的,其中的userIds所有用户都是列,所有movieIds是行,相应的评级是价值?

UserId 1 2 3 4 5 6 7 8 9 10 
MovieId                      

    1 5.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 
    2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 5.0 
    3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 4.5 0.0 
    4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 
    5 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 

如果用户不评价一部电影我还是希望他们在基质中,如用户数8,谁没有评价一部电影。

+0

我可以生成上面的矩阵,但是只有评级至少有1部电影和电影的用户被评为至少一次,这两行: df1 = pd.read_sql(session.query(Rating)。声明,session.bind) print(df1.pivot(column ='movie_id',index ='user_id',values ='rating')) 但我想获得所有用户和所有电影,无论多少他们评估或评估过的次数。 – LarmadVara

回答

2

哇,这是很多问题!我们一次做一件事。

所以,你想用户和电影。酷酷。

这是我会怎么定义的车型:

from werkzeug.security import check_password_hash, generate_password_hash 
from . import db # grab sqlalchemy 

class User(db.Model, UserMixin): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    username = db.Column(db.String(), unique=True) # Can something be nullable and unique? I think it can be, or that this would be allowed, but still, probably want this to be not null 
    password_hash = db.Column(db.String(128)) # Likewise, make password HASH not nullable. Don't store plaintext passwords, seriously. 

    @property 
    def password(self): 
     raise (AttributeError('"password" is not a readable attribute')) 

    @password.setter 
    def password(self, password): 
     self.password_hash = generate_password_hash(password) 

    def verify_password(self, password): 
     return (check_password_hash(self.password_hash, password)) 

    movies = db.relationship('Movie', secondary='ratings') # n:m relationship 


class Movie(db.Model): 
    __tablename__ = 'movies' 
    id = db.Column(db.Integer, primary_key=True) 
    # ... 
    users = db.relationship('User', secondary='ratings') # n:m relationship 
    # ... 


class Rating(): 
    __tablename__ = 'ratings' 
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True) 
    movie_id = db.Column(db.Integer, db.ForeignKey('movies.id'), primary_key=True) 
    # The following defines a User.ratings attribute that points to this object 
    # The backref loads the object dynamically, but accessing the link object directly joins both the user and movie 
    user = db.relationship(User, backref=db.backref("ratings", lazy='dynamic'), lazy='joined') 
    # Likewise for Movies 
    movie = db.relationship(Movie, backref=db.backref("ratings", lazy='dynamic'), lazy='joined') 
    # Store User rating information here, as a part of link: 
    rating = db.Column(db.Float, default='0') # Could be nullable, or default could be something impossible like "-1" to distinguish, if needed. 

好吧,冷静......所以现在你可以做这样的东西:

user = current_user or User.query.filter_by(id=3087).first() 
Rating.query.filter(Rating.user == user).all() # all ratings by a user (current user or user id = 3087, in this case) 
# Same as: 
user.ratings # All ratings by a user 

User.query.filter_by(id=user.id).first().ratings # list of all ratings for a user 

great_movie = Movie.query.filter_by(name="Birdemic: Shock and Terror").first() 
Movie.query.filter_by(id=great_movie.id).first().ratings # all ratings for a movie (Birdemic: Shock and Terror, in this case) 
# Same as: 
great_movie.ratings 

您可以定义阵法作为视图,或者甚至可以通过将矩阵生成代码作为模型类的静态方法为用户和电影创建子矩阵:

因此,您可以将行为编码为:

<User Object>.ratings_matrix() 

例子(伪只):

@app.route('/matrix', methods=['GET']) 
def matrix(): 
    # define pandas matrix, and iteratively fill it with ratings: 
    matrix = Matrix() # ?? Idk 

    for user in User.query.all(): 
     for movie in Movie.query.all(): 
      rating = Rating.query.filter_by(user_id=user.id, movie_id=movie.id).first().rating # find by ids, then get actual rating value (Rating.rating) 

      if rating: 
       # add rating to matrix at correct position (user.id, movie.id) 
       matrix[user.id, movie.id] = rating 
      else: 
       matrix[user.id, movie.id] = 0 

    return(render_template('ratings_matrix.html', matrix=matrix)) # implies 'templates/ratings_matrix.html' 

还是喜欢,你可以有预先创建,存储矩阵(也许腌?),然后从数据库或缓存整个检索。真的!

希望这会有所帮助!

+0

非常感谢!它真的帮了大忙! :) – LarmadVara