我正在使用Miguel Gringberg的书“Flask Web Development”开发一个社交烧瓶网络应用程序。我无法为帖子和评论实现类似的功能。我尝试复制书中的跟随功能,但我得到一个sqlalchemy错误,说明"在Post模型中的Post.liked列中找不到关系" (我相信还有更多错误)这是我的models.py代码。
# Set website access permissions
class Permission:
FOLLOW = 0x01
COMMENT = 0x02
WRITE_ARTICLES = 0x04
MODERATE_COMMENTS = 0x08
ADMINISTER = 0x80
# User roles
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
default = db.Column(db.Boolean, default=False, index=True)
permissions = db.Column(db.Integer)
users = db.relationship('User', backref='role', lazy='dynamic')
# Crete roles in the db
@staticmethod
def insert_roles():
roles = {
'User': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES, True),
'Moderator': (Permission.FOLLOW |
Permission.COMMENT |
Permission.WRITE_ARTICLES |
Permission.MODERATE_COMMENTS, False),
'Administrator': (0xff, False)
}
for r in roles:
role = Role.query.filter_by(name=r).first()
if role is None:
role = Role(name=r)
role.permissions = roles[r][0]
role.default = roles[r][1]
db.session.add(role)
db.session.commit()
def __repr__(self):
return '<Role %r>' % self.name
# Follows association table
class Follow(db.Model):
__tablename__ = 'follows'
follower_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
followed_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
class Like(db.Model):
__tablename__ = 'likes'
post_liked_id = db.Column(db.Integer, db.ForeignKey('posts.id'), primary_key=True)
comment_liked_id =db.Column(db.Integer, db.ForeignKey('comments.id'), primary_key=True)
liker_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
# Users table
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key= True, autoincrement=True)
first_name = db.Column(db.String(64))
last_name = db.Column(db.String(64))
dob = db.Column(db.Date)
gender = db.Column(db.String(64))
nationality = db.Column(db.String(64))
residence = db.Column(db.String(64))
postal_code = db.Column(db.String(64))
username = db.Column(db.String(64), unique=True)
email = db.Column(db.String(64), unique=True)
password_hash = db.Column(db.String(128))
member_since = db.Column(db.DateTime(), default=datetime.utcnow)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
confirmed = db.Column(db.Boolean, default=False)
location = db.Column(db.String(64))
about_me = db.Column(db.Text())
last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
bio = db.Column(db.String(100))
profile_pic = db.Column(db.String, default=None)
profile_pic_url = db.Column(db.String, default=None)
posts = db.relationship('Post', backref='author', lazy='dynamic')
followed = db.relationship('Follow', foreign_keys=[Follow.follower_id], backref=db.backref('follower', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
followers = db.relationship('Follow', foreign_keys=[Follow.followed_id], backref=db.backref('followed', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
comments = db.relationship('Comment', backref='author', lazy='dynamic')
liker = db.relationship('Like', backref='liker', lazy='dynamic')
# Define default role for users
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
if self.role is None:
if self.email == 'hardingalex@live.com':
self.role = Role.query.filter_by(permissions=0xff).first()
if self.role is None:
self.role = Role.query.filter_by(default=True).first()
self.follow(self)
# User account confirmation
def generate_confirmation_token(self, expiration=86400):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'confirm': self.id})
def confirm(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token)
except:
return False
if data.get('confirm') != self.id:
return False
self.confirmed = True
db.session.add(self)
return True
# Password hashing and verification
@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)
# Load and remember logged in user
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Evaluate whether a user has a given permission
def can(self, permissions):
return self.role is not None and (self.role.permissions & permissions) == permissions
def is_administrator(self):
return self.can(Permission.ADMINISTER)
#Refresh users last visit
def ping(self):
self.last_seen = datetime.utcnow()
db.session.add(self)
#Connection helper methods
def follow(self, user):
if not self.is_following(user):
f = Follow(follower=self, followed=user)
db.session.add(f)
def unfollow(self, user):
f = self.followed.filter_by(followed_id=user.id).first()
if f:
db.session.delete(f)
def is_following(self, user):
return self.followed.filter_by(followed_id=user.id).first() is not None
def is_followed_by(self, user):
return self.followers.filter_by(follower_id=user.id).first() is not None
#get followed posts
@property
def followed_posts(self):
return Post.query.join(Follow, Follow.followed_id == Post.author_id).filter(Follow.follower_id == self.id)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text())
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
comments = db.relationship('Comment', backref='post', lazy='dynamic')
liked = db.relationship('Like', foreign_keys=[Like.liker_id], backref=db.backref('liker', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
likers = db.relationship('Like', foreign_keys=[Like.post_liked_id], backref=db.backref('liked', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
# Post Likes helper methods
def like_post(self, post):
if not self.is_liking_post(post):
l = Like(liker=self, liked=post)
db.session.add(l)
def unlike_post(self, post):
l = self.liked.filter_by(post_liked_id=post.id).first()
if l:
db.session.delete(l)
def is_liking_post(self, post):
return self.liked.filter_by(post_liked_id=post.id).first() is not None
def is_liked_by(self, post):
return self.likers.filter_by(liker_id=post.id).first() is not None
#comments model
class Comment(db.Model):
__tablename__ = 'comments'
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime,index=True, default=datetime.utcnow)
disabled = db.Column(db.Boolean)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
liked = db.relationship('Like', foreign_keys=[Like.liker_id], backref=db.backref('liker', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
likers = db.relationship('Like', foreign_keys=[Like.comment_liked_id], backref=db.backref('liked', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
#Comment Likes helper methods
def like_comment(self, comment):
if not self.is_liking_comment(comment):
c = Like(liker=self, liked=comment)
db.session.add(c)
def unlike_comment(self, comment):
c = self.liked.filter_by(comment_liked_id=comment.id).first()
if c:
db.session.delete(c)
def is_liking_comment(self, comment):
return self.liked.filter_by(comment_liked_id=comment.id).first() is not None
def is_liked_by(self, comment):
return self.likers.filter_by(liker_id=comment.id).first() is not None
答案 0 :(得分:0)
首先,你要为帖子和评论混合喜欢。这不会顺利。我建议您使用两个单独的多对多关系将评论喜欢与评论喜欢分开。
您遇到的错误是因为您没有正确实现多对多关系。例如,要表示帖子喜欢,您在用户和帖子之间存在多对多关系。例如,关联表可以被称为PostLikes
,它将有两个外键user_id
和post_id
(如果你想记录类似的时间,也可能是一个时间戳)。
在用户方面,您可以或多或少地定义关系:
class User:
post_likes = db.relationship('PostLikes', backref=db.backref('user', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
在帖子方面,它将是:
class Post:
user_likes = db.relationship('PostLikes', backref=db.backref('post', lazy='joined'),
lazy='dynamic', cascade='all, delete-orphan')
那么,给定一个用户,你可以说user.post_likes
,这会给你一个db查询,返回用户喜欢的所有帖子。如果有帖子,您可以说post.user_likes
以获取喜欢该帖子的所有用户。
然后,您将重复上述所有评论。