一. 我们想添加的功能
之前我们完成了用户之间的相互关注, 我们想在首页增加一个选项如下图:
如果已登录用户访问主页, 我们给两个选项卡, 点击All选项, 显示数据库中所有的文章; 点击Followers选项卡, 显示当前用户所关注的用户的文章和自己的文章。
那我们如何实现上述功能?
答案是我们借助cookie(ps:http://blog.csdn.net/sinat_34927324/article/details/53835711)来实现上述功能, 大体思路如下:
我们点击All选项, main.show_all路由把cookie设成False;点击Followers选项, main.show_followed路由把cookie设成True。然后重定向到主页, 在main.index路由中,根据cookie的值分别来选择显示所有用户还是显示当前登录用户所关注的用户。
二. cookie的处理
@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 @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 @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 = 返回该用户所关注的用户的文章的查询 else: query = Post.query pagination = query.order_by(Post.timestamp.desc()).paginate(page, per_page=current_app.config['FLASKY_POST_PER_PAGE', error_out=False]) posts = pagination.items return render_template('index.html', form=from, posts=posts, show_followed=show_followed, pagination=pagination)
代码解释:
- 未登录用户访问主页, show_followed值为False, query的值是对所有文章的查询, 显示的就是所有的文章。
- 已登录用户访问主页, 一开始cookie取默认值False, 显示的也是所有文章。
- 已登录用户点击All选项卡, 把cookie设置为False, 然后重定向到主页, 显示的还是所有文章。
- 已登录用户点击Followers选项卡, 把cookie设置为True, query的值是对登录用户所关注的用户的文章的查询, 显示的就是所关注用户的文章了。
三. 查询用户所关注用户的所有文章
那么我们如何查询用户所关注的用户的文章呢?
Post.query.join(Follow, Post.author_id == Follow.followed_id).filter(Follow.follower_id == self.id)
Post.query表示查询的是Post记录;
为了优化查询, flask-sqlalchemy先执行过滤, 先把Follow表进行过滤,只留下当前用户作为关注者的记录;
然后再把所得的Follow记录与Post表进行联结, 联结条件是Post.author_id == Follow.followed_id, 联结以后所得到的表就是我们的查询结果, 我们就得到了当前用户所关注的用户的所有文章, 我们把该语句写进User模型里:
class User(UserMixin, db.Model): #... @property def followed_posts(self): return Post.query.join(Post.author_id == Follow.followed_id).filter(Follow.follower_id = self.id)
所以标题二中的那句伪代码应该是query = current_user.followed_posts
我们不止想显示当前用户所关注的用户的文章, 还希望显示自己的文章, 其实这也简单, 只要再构造函数中让用户自己关注自己就可以了:
class User(UserMixin, db.Model): def __init__(self): #... self.follow(self)
但是问题又来了, 我们之前创建的用户都没有关注自己, 其实也简单, 只要创建一个类函数, 遍历所有用户进行修改即可:
class User(UserMixin, db.Model): #... @staticmethod def add_self_follow(): for user in User.query.all(): if not user.is_following(user): user.follow(user) db.session.add(user) db.session.commit()
然后在命令行中执行:
>>User.add_self_follow()
我们就把所有用户进行了自我关注。
进行自我关注以后, 用户页面的关注者和非关注者个数都要减一{{user.followers.count() - 1}}, followers.html中遍历所有关注者和被关注者时都要注意加上{% if follow['user'] != user%}这个条件。
四. 修改主页index.html
路由都处理完了, 最后我们来修改主页, 显示All和Followers标签:
<div class="post-tag"> <ul class="nav navbar-nav"> <li {% if not show_followed %} class="active"{% endif %}><a href="{{url_for('main.show_all')}}">All</a></li> {% if current_user.is_authenticated %} <li {% if show_followed %} class="active"{% endif %}><a href="{{url_for('main.show_followed')}}">Followers</a></li> {% endif %} {% include '_posts.html' %} </ul> </div>
代码解释:
用户登录以后才显示Followers标签, 如果传过来的show_followed是False, 那么说明显示的是所有的文章, 这时All标签的class=“active”突出出来;如果传过来的show_followed是True, 那么说明显示的是所关注用户的文章, 这时Followers标签的class=“active”突出出来;