flask学习十一关注着

Erick-LONG Erick-LONG     2022-09-03     410

关键词:

数据库关系

1.1多对多关系

添加第三张表(关联表),多对多关系可以分解成原表和关联表之间的两个一对多的关系

多对多仍然使用db.relationship()方法定义,但是secondary参数必须设定为关联表,多对多关系可以在任何一个表中定义,backref参数会处理好关系的另一侧

1.2 自引用关系

如果关系中的两侧都在同一个表中称为自引用关系,在关注中,关系的左侧是用户实体,为关注着,关系的右侧也是用户实体,但是被关注着

本例的关联表是 follows,其中每一行都表示一个用户关注了另一个用户。图中左边表示的一对多关系把用户和 follows 表中的一组记录联系起来,用户是关注者。图中右边表示的一对多关系把用户和 follows 表中的一组记录联系起来,用户是被关注者。

 1.3 高级多对多关系

在多对多关系中需要存储实体之间的额外信息,用户之间的关注可以把时间信息存储在关联表中

app/models.py/Follow 关注关联表模型的实现

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)

app/models.py/User 使用两个一对多关系实现的多对多关系

class User(UserMixin,db.Model):
   。。。。   
# 为了消除外键间的歧义,定义关系时使用foreign_keys指定外键 # db.backref指的是回引Follow模型,lazy='joined'可以实现立即一次性完成从连结查询中加载相关对象 # 如果把joined换成select就会成倍增加数据库查询次数 # lazy='dynamic' 直接返回查询对象,可以在执行查询之前添加过滤器 # cascade 参数配置在父对象上执行的操作对相关对象的影响 # 层叠选项可设定添加用户到数据库会话中,自动把所有的关系对象添加到会话中 # delete-orphan的作用是把默认层叠行为(把对象联结的所有相关对象的外键设为空值),变成删除记录后把指向该记录的实体也删除,这样就有效的销毁的联结 # 'all,delete-orphan'是逗号分隔的层叠选项,表示启用所有默认层叠选项并删除关联记录,all表示除了delete-orphan之外的所有层叠选项, 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')

app/models.py/User 定义关注关系的辅助方法

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): # followed找到联结用户和被关注用户的实例 f = self.followed.filter_by(followed_id=user.id).first() if f : # 销毁用户之间的联结,删除这个对象即可 db.session.delete(f) def is_following(self,user): # 搜索两边指定的用户,如果找到返回True return self.followed.filter_by(followed_id=user.id).first() is not None def is_followed_by(self,user): # 搜索两边指定的用户,如果找到返回True return self.followers.filter_by(follower_id=user.id).first() is not None

 2 在资料页显示关注者

2.1 在用户资料页上部添加关注信息

<p>
            {% 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-primary">关注</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) }}">关注数:<span class="badge">{{ user.followers.count() }}</span></a>
            <a href="{{ url_for('.followed_by',username=user.username) }}">粉丝数:<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">关注了你</span>
            {% endif %}
</p>

用户点击关注按钮后执行/follow/<username>路由

app/main/views.py “关注”路由和视图函数

# 用户点击关注按钮后执行/follow/<username>路由
@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('用户不存在')
        return redirect(url_for('.index'))
    if current_user.is_following(user):
        flash('你已经关注他了')
        return redirect(url_for('.user',username=username))
    current_user.follow(user)
    flash('关注成功')
    return redirect(url_for('.user',username=username))

# 用户点击取消关注按钮后执行/unfollow/<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('用户不存在')
        return redirect(url_for('.index'))
    if not current_user.is_following(user):
        flash('你还没有关注他')
        return redirect(url_for('.user',username=username))
    current_user.unfollow(user)
    flash('取消关注成功')
    return redirect(url_for('.user',username=username))

# 用户点击关注者数量后调用/followers/<username>
@main.route('/followers/<username>')
def followers(username):
    user = User.query.filter_by(username=username).first()
    if user is None:
        flash('用户不存在')
        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='粉丝列表',
                           endpoint='.followers',pagination=pagination,follows=follows)


# 用户点击粉丝数量后调用/followed/<username>
@main.route('/followed_by/<username>')
def followed_by(username):
    user = User.query.filter_by(username=username).first()
    if user is None:
        flash('用户不存在')
        return redirect(url_for('.index'))
    page = request.args.get('page',1,type=int)
    pagination = user.followed.paginate(page,per_page=current_app.config['FLASKY_FOLLOWERS_PER_PAGE'],error_out=False)
    follows=[{'user':item.followed,'timestamp':item.timestamp} for item in pagination.items]
    return render_template('followers.html',user=user,title='关注列表',
                           endpoint='.followed_by',pagination=pagination,follows=follows)
{% extends "base.html" %}
{% import "_macros.html" as macros %}

{% block title %}Flasky - {{ title }} {{ user.username }}{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>{{ title }} {{ user.username }}</h1>
</div>
<table class="table table-hover followers">
    <thead><tr><th>用户</th><th>时间</th></tr></thead>
    {% for follow in follows %}
    <tr>
        <td>
            <a href="{{ url_for('.user', username = follow.user.username) }}">
                <img class="img-rounded" src="{{ follow.user.gravatar(size=32) }}">
                {{ follow.user.username }}
            </a>
        </td>
        <td>{{ moment(follow.timestamp).format('YYYY年M月D日 HH:mm:ss') }}</td>
    </tr>
    {% endfor %}
</table>

<div class="pagination">
    {{ macros.pagination_widget(pagination, endpoint, username = user.username) }}
</div>

{% endblock %}
Followers.html
.table.followers tr {
    border-bottom: 1px solid #e0e0e0;
}

2.3使用数据库联结查询所关注用户的文章

app/models.py

class User(UserMixin,db.Model):
  # 定义方法为属性,找到关注用户所发表的文章,SQLalchemy 首先收集所有的过滤器,再以最高效的方式生成查询
    @property
    def followed_post(self):
        return Post.query.join(Follow,Follow.followed_id==Post.author_id).filter(Follow.follower_id == self.id)

2.4 

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 # 显示分页需要用到sqlachemy提供的paginate方法 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)

app/main/views.py 设定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():
    # cookies只能在响应中设置,需要用make_response创建响应对象
    resp = make_response(redirect(url_for('.index')))
    # max_age设定cookies的过期时间,30*24*60*60为30天
    resp.set_cookie('show_followed','1',max_age=30*24*60*60)
    return resp

index.html 添加两个导航选项卡,分别调用all和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>
    {% include '_posts.html' %}
    </div>

在关注列表显示自己的文章

app.models.py 构建用户时把自己设为自己的关注着

class User(UserMixin,db.Model):
    def __init__(self,**kwargs):
     。。。
# 构建用户时把自己设为自己的关注者 self.follow(self)

添加函数更新现有用户

class User(UserMixin,db.Model):
  。。。   
# 把用户设为自己的关注者 @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()

在shell中运行这个函数更新数据库

python manage.py shell
User.add_self_follows()

 为保证数据准确需要在粉丝数,关注数中减去1,关注和粉丝列表也要除去自己

user.html   user.followers.count() - 1 

<a href="{{ url_for('.followers',username=user.username) }}">粉丝数:<span class="badge">{{ user.followers.count() - 1 }}</span></a>
<a href="{{ url_for('.followed_by',username=user.username) }}">关注数:<span class="badge">{{ user.followed.count() - 1 }}</span></a>
followers.html 中添加判断以不显示自己
{% if follow.user != user %}

codecombat试玩全攻略第十一关再次迷宫经历

   第十一关再次迷宫经历  我们还是看提示的蓝色箭头,向右,向上,再向右,向下,再向右。后面都是一样了,这样就构成了一个循环,嗯,还是whileTrue,开始吧。代码如下:1#使用loop循环穿越迷宫!23whileTrue:4hero.mov... 查看详情

flask定义数据关系(多对一)(代码片段)

多对一一对多关系反过来就是多对一关系,这两种关系模式分别从不同的视角出发。一个作者拥有多篇文章,反过来就是多篇文章属于同一个作者。为了便于区分,我们使用居民和城市来演示多对一关系:多个居民住在同一个城... 查看详情

二十开始flask项目

新建Flask项目。设置调试模式。理解Flask项目主程序。使用装饰器,设置路径与函数之间的关系。使用Flask中render_template,用不同的路径,返回首页、登录员、注册页。fromflaskimportFlask,render_templateapp=Flask(__name__)@app.route(‘/‘)definde... 查看详情

写给十八岁以下的你

...信写给不知名的你。现在的你或刚进大学校园,或仍等待一关又一关的学测,好进梦想中的校园。然而,2008年9月源自华尔街的金融海啸,让台北或高雄的你,开始迷惘未来。四年后人生什么样?十年后世界又是何种风貌? &... 查看详情

sqlalchemy学习-9.一对多和多对一关系(代码片段)

前言一对多和多对一关系一对多关系一对多关系表设计,一个Parent类关联多个Child类fromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemyimportcreate_engine,Column,Integer,String,ForeignKeyfromsqlalchemy.ormimportrelatio 查看详情

python面试必考重点之列表,元组和字典第十一关——del和pop都可以用来删除列表元素,那么它们有什么区别呢(代码片段)

面试题第十一关:第一部分——考点:del的用法2.pop的用法第二部分——面试题:1.面试题一:del和pop都可以用来删除列表元素,那么它们有什么区别呢第三部分——解析:面试题一之del和pop都可以用来删... 查看详情

flask框架的学习

---恢复内容开始---第一个flask程序讲解:1.第一次创建项目的时候,要添加flask的虚拟环境。添加虚拟环境的时候,一定要选择到python这个执行文件。比如你的flask的虚拟环境的目录在/User/Virtualenv/flask-env/bin/python。2.flask程序代码... 查看详情

flask学习(二)

安装了flask扩展  以及flask-bootstrap默认情况下,flask在template文件夹寻找模板。flask加载的是Jinja2模板,该模板引擎在flask中由函数render_template集成所以在文件中这样渲染模板fromflaskimportFlask,render_template#...@app.route(‘/‘)defind... 查看详情

flask学习三

使用flask-bootstrap集成Bootstrappipinstall flask-bootstrap安装后即可继承使用Bootsftrap所有文件的基模版 fromflaskimportFlask,render_templatefromflask.ext.bootstrapimportBootstrapapp=Flask(__name__)bootstrap=Boots 查看详情

老男孩-第一关测试

课前考试题汇总如何成为高手?针对性刻意练习学习的过程注定是辛苦的,分享可以得到即时反馈,这是良性循环的开始学习过程必须养成做笔记的习惯,重复的力量是无穷怕,好的习惯只需要21天即可培养出来技术的提升只是... 查看详情

flask学习

最近学习flask框架,是照着图灵丛书《FlaskWeb开发》来学的。照着第2章写了个简单的框架#_*_coding:utf-8_*_fromflaskimportFlaskapp=Flask(__name__)@app.route(‘/‘)defindex():return‘<h1>hello</h1>‘@app.route(‘/hello‘)defhello():ret 查看详情

flask学习:flask入门(url)

一.flask简介flask是一款非常流行的pythonweb框架,出生于2010年,作者是ArminRonacher,本来这个项目只是作者在愚人节的一个玩笑,后来由于非常受欢迎,进而成为一个正式的项目。目前为止最新的版本是1.0.2flask自2010年发布第一个版... 查看详情

flask学习app代码备份

#!/usr/bin/python#-*-coding:UTF-8-*-fromflaskimportFlask,url_forfromflaskimportrequestfromflask_scriptimportManagerfromflaskimportrender_templatefromthreadingimportThreadimportrequestsimportjsonfromfl 查看详情

flask学习

flask简介Flask是一个基于Python开发并且依赖jinja2模板和WerkzeugWSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应... 查看详情

flask学习笔记——配置管理

1、硬编码:app=Flask(__name__)#app.config是flask.config.Config类的实例,继承自内置数据结构dictapp.config[‘DEBUG‘]=True2、参考——flask.config.Config类:classConfig(dict):"""Worksexactlylikeadictbutprovideswaystofillitfromfileso 查看详情

flask学习

-fromflaskimportFlask+fromflaskimportFlask,render_template-fromflaskimportrequest-fromflaskimportmake_response-fromflaskimportabort-fromflaskimportredirect-#__name__参数决定程序的根目录app=Flask(__name__)-#@app 查看详情

flask学习-42.flask-restx快速入门(代码片段)

前言Flask-restfull是flask框架开发接口的一个框架,Flask-RESTPlus是Flask-restfull升级版,可以生成swagger在线文档了。但是Flask-RESTPlus这个项目不再维护了,迁移到Flask-RESTX了。Flask-RESTX与Flask-RESTPlus的API保持100%兼容。环境安装... 查看详情

flask_appbuilder的学习:安装

Flask_appbuilder学习       通常对于一个后台管理项目来说,大部分的功能都是对数据进行增删改查操作, 而这些操作的代码大致是一样的,唯一变化的是数据,Flask_appbuilder就是为了减少这段重复代码... 查看详情