flask_关注者
表的模型实现
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 User(UserMixin,db.Model): #... 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')
关注关系的辅助方法
class User(UserMixin,db.Model): #... #关注 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
在资料页中显示关注者
app/templates/user.html
{% if current_user.can(Permission.FOLLOW) and user != current_user %} {% if not current_user.is_following(user) %} <a href="{{ url_for('.follow',username=user.username) }}" class="btn btn-default">关注</a> {% else %} <a href="{{ url_for('.unfollow',username=user.username) }}" class="btn btn-default">取消关注</a> {% endif %} {% endif %} <a href="{{ url_for('.followers',username=user.username)}}"> Followers:<span class="badge">{{ user.followers.count() }}</span> </a> <a href="{{ url_for('.followed_by',username=user.username) }}"> Following:<span class="badge">{{ user.followed.count() }}</span> </a> {% if current_user.is_authenticated and user != current_user and user.is_following(current_user)%} |<span class="label label-default">Follows you</span> {% endif %}
app/main/views.py: ‘关注’路由和视图函数
@main.route('/follow/<username>') @login_required @permission_required(Permission.FOLLOW) def follow(username): user = User.query.filter_by(username=username).first() if user is None: flash(u'用户不存在') return redirect(url_for('.index')) if current_user.is_following(user): flash(u'已关注') return redirect(url_for('.user',username=username)) current_user.follow(user) flash('You are now following %s.'%username) return redirect(url_for('.user',username=username))
@main.route('/unfollow/<username>') @login_required @permission_required(Permission.FOLLOW) def unfollow(username): user = User.query.filter_by(username=username).first() if user is None: flash('Invalid user.') return redirect(url_for('.index')) if not current_user.is_following(user): flash('You are not following this user.') return redirect(url_for('.user', username=username)) current_user.unfollow(user) flash('You are not following %s anymore.' % username) return redirect(url_for('.user', username=username))
@main.route('/followers/<username>') def followers(username): user = User.query.filter_by(username=username).first() if user is None: flash('Invalid user.') return redirect(url_for('.index')) page = request.args.get('page', 1, type=int) pagination = user.followers.paginate( page, per_page=current_app.config['FLASKY_FOLLOWERS_PER_PAGE'], error_out=False) follows = [{'user': item.follower, 'timestamp': item.timestamp} for item in pagination.items] return render_template('followers.html', user=user, title="Followers of", endpoint='.followers', pagination=pagination, follows=follows)
@main.route('/followers/<username>') def followers(username): user = User.query.filter_by(username=username).first() if user is None: flash('Invalid user.') return redirect(url_for('.index')) page = request.args.get('page', 1, type=int) pagination = user.followers.paginate( page, per_page=current_app.config['FLASKY_FOLLOWERS_PER_PAGE'], error_out=False) follows = [{'user': item.follower, 'timestamp': item.timestamp} for item in pagination.items] return render_template('followers.html', user=user, title="Followers of", endpoint='.followers', pagination=pagination, follows=follows)
使用数据库联结查询所关注用户的文章
要想只查看关注用户的文章需要把posts表和follows表联结起来查询
class User(UserMixin,db.Model): #.. @property def followed_posts(self): return Post.query.join(Follow,Follow.followed_id == Post.author_id)\ .filter(Follow.follower_id == self.id)
Post表联结Follow表 Follow表被关注 = 文章作者的id 查找 Follow表中关注者的id
在首页显示所关注用户的文章
app/main/views.py:显示所有博客文章或只显示所关注用户的文章
@main.route('/', methods=['GET', 'POST']) def index(): #... show_followed=False if current_user.is_authenticated: show_followed = bool(request.cookies.get('show_followed','')) if show_followed: query = current_user.followed_posts else: query = Post.query pagination = query.order_by(Post.timestamp.desc()).paginate( page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'], error_out=False) posts = pagination.items return render_template('index.html', form=form, posts=posts,show_followed=show_followed, pagination=pagination)
决定显示所有文章还是只显示所关注用户文章的选项存储在cookie的show_followed字段中,如果其值为非空字符串,则表示只显示所关注用户的文章。
query的值决定最终获取所有博客的查询,或是获取过滤后的博客文章查询
app/main/views.py:查询所有文章还是所关注用户的文章
@main.route('/all') @login_required def show_all(): resp = make_response(redirect(url_for('.index'))) resp.set_cookie('show_followed','',max_age=30*24*60*60) return resp
resp返回一个响应,然后为它的cookie设置为 show_followed为空,过期时间为一个月
@main.route('/followed') @login_required def show_followed(): resp = make_response(redirect(url_for('.index'))) resp.set_cookie('show_followed','1',max_age=30*24*60*60) return resp
resp返回一个响应,然后为它的cookie设置为 show_followed不为空,过期时间为一个月,表示只显示只看所关注用户的文章
接下来改动模板
<div class="post-tabs"> <ul class="nav nav-tabs"> <li {% if not show_followed %}class="active"{% endif %} ><a href="{{ url_for('.show_all') }}" >全部</a></li> {% if current_user.is_authenticated %} <li {% if show_followed %}class="active"{% endif %}><a href="{{ url_for('.show_followed') }}">关注</a> </li> {% endif %} </ul>
app/model.py:构建用户时把用户设为自己的关注者
def __init__(self,**kwargs): self.follow(self)
app/models.py:把用户设为自己的关注者
@staticmethod def add_self_follows(): for user in User.query.all(): if not user.is_following(user): user.follow(user) db.session.add(user) db.session.commit()
(venv) >python manage.py shell >>> User.add_self_follows()
把关注者数量减一
<a href="{{ url_for('.followers',username=user.username)}}">j Followers:<span class="badge">{{ user.followers.count() - 1 }}</span>
·