我希望有一位可以为不同电影评分的用户。电影可以有很多评级;用户可以为很多电影评分。
我认为它看起来像这样:
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))
如果这是正确的,我将如何查询这些表以获取每部电影上的所有用户及其评级,然后生成一个pandas数据框,其中所有用户的userIds为列,所有movieId为行,各自的评级为价值?
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 :(得分: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'
或者,您可以预先创建,存储(可能会腌制?)然后从db或缓存整体中检索矩阵。真的是你!
希望这有帮助!