Flask_Web学习梳理总结(下)

简单回顾hello.py与使用大型组织结构的区别,狗书中从第八章的实例后都采用了蓝本的方式处理路由。

import #导入                                                  ---- {分别导入}
basedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)   #初始化程序
app.config['SECRET_KEY'] = 'hard to guess string' #配置       -----{config.py}                                  
migrate = Migrate(app, db)
manager = Manager(app)      #将app连接各个库的初始化            -----{migrate和manager放在manage.py的启动程序上}
bootstrap = Bootstrap(app)         #将app连接各个库的初始化     ------{放在app/__init__.py初始化上}
class NameForm(Form):   #定义表单                              ------{在app/main/forms.py}
class Role(db.Model):
class User(db.Model): #定义模型                                 -------{在app/models.py}
def make_shell_context(): #集成Python shell                    -------{manage.py启动程序上}
def send_async_email(app, msg):
def send_email(to, subject, template, **kwargs): #异步发送邮件  ------{app/email.py上}
@app.errorhandler(404)
@app.errorhandler(500) #处理返回错误模板                         ------{app/main/errors.py}
@app.route('/', methods=['GET', 'POST'])                   
@app.route('/user/<name>') #定义视图函数                         ------{app/main/view.py}

书上的内容跟着敲就好了,这里简单分享看狗书过程踩的一些小坑和增加一个收藏功能的实现过程

遇到的一些坑:

  • 数据迁移db upgrade不起作用,更新现有数据库表的粗暴方式是先删除旧表再重新创建
>>>
from manage import db
db.drop_all()
db.create_all()
exit()
  • 第八章代码配置发送邮箱的代码,原代码里的谷歌邮箱已经不能用了(授权码有时会自动更新)
class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    MAIL_SERVER = 'smtp.qq.com'
    MAIL_PORT = 465
    MAIL_USE_TLS = False
    MAIL_USE_SSL = True
    MAIL_USERNAME = "123456789@qq.com"
    MAIL_PASSWORD = "自己邮箱的授权码"
    FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
    FLASKY_MAIL_SENDER = 'Admin <123456789@qq.com>'
    FLASKY_ADMIN = "123456789@qq.com"
  • flask web第11章节遇到博文表单不显示出来

主要是因为在Role没有建立起来的时候(此时在python manage.py shell中,执行Role.query.all()应该得到的是[]),你就先注册了用户,那么此时你的用户角色肯定什么都不是。 故无法显示表单或者文章列表。因此你需要:首先在python manage.py shell中执行Role.insert_roles(), 查询Role.query.all()之后确保得到的结果是[<Role…><><>],之后再注册用户; 如果你之前的db中已经包含了你的邮箱或用户名,那么请现在shell中执行

from manage.py import db
db.drop_all() 
db.create_all()

链接:https://www.zhihu.com/questio…

简单实现一个收藏功能:

希望在狗书的基础上给每条博客增加一个收藏按钮,然后在导航栏增加一行“我的收藏”来显示用户收藏的那些博客,下图是我自己改的收藏页面。
《Flask_Web学习梳理总结(下)》

首先我们要在博客上增加一个收藏/取消收藏按钮,如果未收藏则显示“收藏”,已经收藏了则显示“未收藏”,改动放在需要被渲染的_post.html独立页面上

div class="post-content">
     <div class="post-date">{{ moment(post.timestamp).fromNow() }}</div>
     ...
     <div class="post-save">
     {% if current_user.is_authenticated %}
          {% if not current_user.is_saving(post) %}
          <a href="{{ url_for('.save', postid=post.id) }}" class="btn btn-danger btn-xs">Save</a>
          {% else %}
          <a href="{{ url_for('.unsave', postid=post.id) }}" class="btn btn-danger btn-xs">Unsave</a>
          {% endif %}
     {% endif %}
     </div>

判断是否已经收藏过的方法.is_saving(post)需要被写进User模型里,所以我们要考虑一下如何更新Model部分。首先考虑到一个user可以收藏多个post,一个post也可以被不同的user收藏,所以这是一个多对多的关系。多对多关系可以使用定义一对多关系的 db.relationship() 方法进行定义,但是这样定义得到的关联表是一个简单的表,不是模型,会被SQLAlchemy 自动接管。想要储存一些额外的信息,例如user收藏post的时间。为了能处理这些额外的信息,我们必须提升关联表的地位,使关联表变成可访问的模型。表示user与post收藏关系的关联表,使用 Save 模型表示。

class Save(db.Model):
    __tablename__ = 'saves'
    saver_id = db.Column(db.Integer, db.ForeignKey('users.id'),
                         primary_key=True)
    saved_id = db.Column(db.Integer, db.ForeignKey('posts.id'),
                         primary_key=True)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    
class User(UserMixin, db.Model):#一个用户可以收藏多篇博客 saveds表示被收藏的博客们
    ...
    saveds = db.relationship('Save',
                             backref=db.backref('saver', lazy='joined'),
                             lazy='dynamic',
                             cascade='all, delete-orphan')
                             
class Post(db.Model): #一篇博客可以被多个用户收藏  savers表示收藏这条博客的用户们
    ...
    savers = db.relationship('Save',
                             backref=db.backref('saved', lazy='joined'),
                             lazy='dynamic',
                             cascade='all, delete-orphan')                                                    
                             

另外.is_saving(post)方法也需要写进User模型里来进行判断当前这个用户是否已经收藏过这篇博客

class User(UserMixin, db.Model): #self表示当前用户在收藏过得博客们里找特定的post
   ...
   def is_saving(self, post):
        return self.saveds.filter_by(
            saved_id=post.id).first() is not None

根据html里面的内容,如果已经收藏过返回true则显示“取消收藏”按钮并返回main.unsave路由;反之则返回main.save路由。这两个路由是来实现收藏博客/取消收藏博客这两个功能并将数据写进数据库里,这样我们下次才能从数据库里查询用户是否收藏过此博客并给出相应的反应。

@main.route('/save/<postid>')
@login_required
def save(postid):
    post = Post.query.filter_by(id=postid).first()
    if post is None:
        flash('Invalid post.')
        return redirect(url_for('.index'))
    current_user.savepost(post)   #用户收藏post的方法
    flash('You saved a message')
    return redirect(url_for('.post', id=postid))
    
@main.route('/unsave/<postid>')
@login_required
def unsave(postid):
    post = Post.query.filter_by(id=postid).first()
    if post is None:
        flash('Invalid post.')
        return redirect(url_for('.index'))
    current_user.unsavepost(post) #用户取消收藏post的方法
    flash('You unsaved a message')
    return redirect(url_for('.post', id=postid))

用户收藏/取消收藏post的方法的需要写进User模型里

class User(UserMixin, db.Model):
    ...
    def savepost(self, post):
        if not self.is_saving(post):
            f = Save(saver=self, saved=post)  
            db.session.add(f)

    def unsavepost(self, post):
        f = self.saveds.filter_by(saved_id=post.id).first()
        if f:
            db.session.delete(f)

到这里,我们还需要在导航栏里设置一个Pocket导航元素来显示所有被收藏的博客,并将内容写成分页显示出来
base.html加入导航元素Pocket,点击后返回main.pocket路由

<ul class="nav navbar-nav">
    ...
    <li><a href="{{ url_for('main.pocket') }}"><b>Pocket</b></a></li>  

视图函数处理Pocket路由,并将分页对象传入pocket.html

@main.route('/pocket', methods=['GET', 'POST'])
def pocket():
    page = request.args.get('page', 1, type=int)
    show_saved = True
    query = current_user.saved_posts    #获得所有收藏posts的方法
    pagination = query.order_by(Post.timestamp.desc()).paginate(
        page, per_page=current_app.config['FLASKY_POCKETS_PER_PAGE'],
        error_out=False)
    posts = pagination.items
    return render_template('pocket.html', posts=posts,
                           show_save=show_saved, pagination=pagination)

所以我们还需要在User再加一个.save_posts方法来获取所有收藏的文章展示在pocket.html里

class User(UserMixin, db.Model):
    ...
    @property
    def saved_posts(self):   #联结查询,Post为最后获取内容,从Save查询用户id的所有收藏记录,最后联结过滤
        return db.session.query(Post).select_from(Save). \
            filter_by(saver_id=self.id).join(Post)

最后只需要在pocket.html渲染就好了。
这段时间都在写研究生要投的期刊论文,flask只是抽空自己学学,以后会更新自己专业领域的多目标优化内容和智能算法,很多地方可能没讲清楚,但最要的是能让自己更好的理解。最后放几张总结的脑图和自己基于狗书上的修改轻博客。主要是换了一些板式,增加图片上传,匿名评论和收藏功能。
github地址:https://github.com/kugua233/L…

狗书上总结的脑图

《Flask_Web学习梳理总结(下)》

《Flask_Web学习梳理总结(下)》

《Flask_Web学习梳理总结(下)》

《Flask_Web学习梳理总结(下)》

《Flask_Web学习梳理总结(下)》

《Flask_Web学习梳理总结(下)》

    原文作者:kugua233
    原文地址: https://segmentfault.com/a/1190000014440442
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞