2017-04-27 59 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