简体   繁体   English

我的数据库关系如何? 烧瓶SQLAlchemy

[英]How would my database relationship look like. Flask sqlalchemy

I want to have a User who can rate different movies. 我想要一个可以为不同电影评分的用户。 A movie can have many ratings; 电影可以有很多等级。 a user can rate many movies. 用户可以为许多电影评分。

I thought it would look like this: 我认为它看起来像这样:

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

If that is right, how would I query these tables to get all users and their ratings on each movie and then generate a pandas dataframe where the userIds of all users are the columns and all movieIds are the rows and the respective rating is the value? 如果是正确的话,我将如何查询这些表以获取每部电影的所有用户及其收视率,然后生成一个pandas数据框,其中所有用户的userId为列,所有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

If a user doesn't have rated a movie I still want them in the matrix, like user number 8, who hasn't rated a single movie. 如果用户没有给电影评分,我仍然希望他们在矩阵中,例如8号用户,但还没有为单个电影评分。

Wow, that's a lot of questions! 哇,这是很多问题! Let's do one thing at a time. 让我们一次做一件事。

So, you want Users and Movies. 因此,您需要用户和电影。 Cool Cool. 酷酷。

Here's how I would define the models: 这是定义模型的方式:

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.

Alright, cool... so now you can do stuff like this: 好吧,酷...所以现在您可以执行以下操作:

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

You can define your matrix method as a view, or maybe even create submatrices for users and movies by placing your matrix generation code as a static method for your model classes: 您可以将矩阵方法定义为视图,甚至可以通过将矩阵生成代码放置为模型类的静态方法来为用户和电影创建子矩阵:

So, like, you could code the behavior to be: 因此,您可以将行为编码为:

<User Object>.ratings_matrix()

Examples (pseudocode only): 示例(仅限伪代码):

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

Or like, you could have the matrix pre-created, stored (pickled maybe?) and then retrieved from the db or cache whole. 或类似,您可以预先创建,存储(腌制?)矩阵,然后从数据库或整个缓存中检索矩阵。 Up to you really! 真的取决于你!

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM