快乐学习
前程无忧、中华英才非你莫属!

Flask入门到精通-Day4

前言-基础增强与回顾
 
1、Request对象
 
Request对象现在该让Flask的请求对象request出场了,这个请求对象封装了从客户端发来的请求报文,我们能从它获取请求报文中的所有数据。 注意请求解析和响应封装实际上大部分是。由Werkzeug完成的,Flask子类化Werkzeug的请求(Request)和响应(Response)对象并添加了和程序相关的特定功能。
我们先从URL说起。假设请求的URL是http://helloflask.com/hello?name=Grey,当Flask接收到请求后,请求对象会提供多个属性来获取URL的各个部分
属性
args
  一个字典,存储通过 URL 查询字符串传递的所有参数
path
u'/hello'
full_path
u'/hello?name=Grey'
host
u'helloflask.com'
host_url
u'http://helloflask.com/'
base_url
u'http://helloflask.com/hello'
url
u'http://helloflask.com/hello?name=Grey'
url_root
u'http://helloflask.com/'
除了URL,请求报文中的其他信息都可以通过request对象提供的属性和方法获取。参考
 
https://www.ztloo.com/2018/09/15/flask入门到精通-day1 中的操作请求数据模块。
 
 
有时候处理表单的时候,因为flask的默认的函数是get的,所以为了支持post,需要声明,要在后面添加methods 。
 
@app.route('/paginate/',methods=['GET', 'POST'])

 
2、钩子
类似于spring里面的aop,类似于单元测试框架里的beforeMethod注解、afterMethod的功能。
flask里有四种钩子
 1、before_first_request: 注册一个函数,在处理第一个请求之前运行.
 2、before_request : 在处理每次请求之前运行
 3、after_request: 如果没有未处理的异常输出,在每次请求之后运行.注册的函数至少需要含有一个参数,这个参数实际上为服务器的响应,且函数中需要返回这个响应参数。
 4、teardown_request: ,同样在每次请求之后运行.注册的函数至少需要含有一个参数,这个参数实际上为服务器的响应,且函数中需要返回这个响应参数
 5、after_this_request:会在这个请求结束后运行。用法如下。
@app.route('/')
def hello_world():
    @after_this_request
    def add_header(response):
        print(response)
        return response
    return 'Hello World!'

3、reponse案例
 
response,响应对象。return‘hello world’就是其响应对象,  https://www.ztloo.com/2018/09/15/flask入门到精通-day1/  中的关于响应。
 
 
   from flask import Flask, make_response, json ...
    @app.route('/foo')
    def foo():
        data = { 'name':'Grey Li',gender':'male' }
        response = make_response(json.dumps(data))
        response.mimetype = 'application/json'
        return response
方法或属性
描述
headers
 表示响应首部
status
 状态码,文本类型
status_code
 状态码,整型
data
  一个调用get_data()的描述符set_data()不应该使用它,最终会被弃用。
get_json(force=False, silent=False, cache=True)
 解析并将数据作为JSON返回。如果mimetype不指示JSON(application / json,请参阅 is_json()),则返回None除非force为true。如果解析失败,on_json_loading_failed()则调用并将其返回值用作返回值。
参数:
  • force - 忽略mimetype并始终尝试解析JSON。
  • 沉默 - 沉默解析错误并返回None 。
  • cache - 存储已解析的JSON以返回后续调用。
is_json
  检查mimetype是否指示JSON数据, application / jsonapplication / * + json
max_cookie_size
  MAX_COOKIE_SIZE配置密钥的只读视图
mimetype
  mimetype(没有charset等的内容类型)
set_cookie(key, value=”, max_age=None, expires=None, path=’/’, domain=None, secure=False, httponly=False, samesite=None)
为响应添加一个cookie

4、蓝图
 
为了在一个或多个应用中,使应用模块化并且支持常用方案, Flask 引入了 蓝图 概念
 
蓝图的基本概念是:在蓝图被注册到应用之后,所要执行的操作的集合。当分配请求 时, Flask 会把蓝图和视图函数关联起来,并生成两个端点之前的 URL 。
 
register_blueprint(蓝图,**选项)
 
参数:
蓝图 - 注册的蓝图。
url_prefix  - 蓝图路由将以此为前缀。
 
 
 
 

5、Flask_login
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
这个回调用于从会话中存储的用户 ID 重新加载用户对象. 如果 ID 无效的话,它应该返回 None (而不是抛出异常)。(在这种情况下,ID 会被手动从会话中移除且处理会继续)
@login_manager.user_loader
def load_user(user_id):
    from models import Admin
    user = Admin.query.get(int(user_id))
    return user
//定义登陆视图是auth.py下的login方法。
login_manager.login_view = 'auth.login'
# login_manager.login_message = 'Your custom message'
//设置快闪消息,用于提示用户:
login_manager.login_message_category = 'warning'

 
6、Flask_mail
from flask_mail import Mail
mail = Mail()
mail.init_app(app)

发送邮件

# -*- coding: utf-8 -*-
from flask import Flask, request
from flask_script import Manager, Shell
from flask_mail import Mail, Message
from threading import Thread
app = Flask(__name__)
app.config['MAIL_DEBUG'] = True             # 开启debug,便于调试看信息
app.config['MAIL_SUPPRESS_SEND'] = False    # 发送邮件,为True则不发送
app.config['MAIL_SERVER'] = 'smtp.qq.com'   # 邮箱服务器
app.config['MAIL_PORT'] = 465               # 端口
app.config['MAIL_USE_SSL'] = True           # 重要,qq邮箱需要使用SSL
app.config['MAIL_USE_TLS'] = False          # 不需要使用TLS
app.config['MAIL_USERNAME'] = 'xxx@qq.com'  # 填邮箱
app.config['MAIL_PASSWORD'] = 'xxxxxx'      # 填授权码
app.config['MAIL_DEFAULT_SENDER'] = 'xxx@qq.com'  # 填邮箱,默认发送者
manager = Manager(app)
mail = Mail(app)
# 异步发送邮件
def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)
@app.route('/')
def index():
    msg = Message(subject='Hello World',
                  sender="xxx@qq.com",  # 需要使用默认发送者则不用填
                  recipients=['x1@qq.com', 'x2@qq.com'])
    # 邮件内容会以文本和html两种格式呈现,而你能看到哪种格式取决于你的邮件客户端。
    msg.body = 'sended by flask-email'
    msg.html = '<b>测试Flask发送邮件<b>'
    thread = Thread(target=send_async_email, args=[app, msg])
    thread.start()
    return '<h1>邮件发送成功</h1>'
if __name__ == '__main__':
    manager.run()
 

 
7、flask_wtf
from flask_wtf import FlaskForm
class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
    password = PasswordField('Password', validators=[DataRequired(), Length(1, 128)])
    remember = BooleanField('Remember me')
    submit = SubmitField('Log in')
 
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('blog.index'))
    form = LoginForm()
    if form.validate_on_submit():
        username = form.username.data
        password = form.password.data
        remember = form.remember.data
        admin = Admin.query.first()
        if admin:
            if username == admin.username and admin.validate_password(password):
                login_user(admin, remember)
                flash('Welcome back.', 'info')
                return redirect_back()
            flash('Invalid username or password.', 'warning')
        else:
            flash('No account.', 'warning')
    return render_template('auth/login.html', form=form)
 
 

 
8、flask_sqlalchemy
 
文章表模型
class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(60))
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)
    can_comment = db.Column(db.Boolean, default=True)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    category = db.relationship('Category', back_populates='posts')
    comments = db.relationship('Comment', back_populates='post', cascade='all, delete-orphan')
首页文章列表展现
@blog_bp.route('/')
def index():
    page = request.args.get('page', 1, type=int)
    per_page = current_app.config['BLUELOG_POST_PER_PAGE']
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=per_page)
    posts = pagination.items
    return render_template('blog/index.html', pagination=pagination, posts=posts)
BLUELOG_POST_PER_PAGE  全局变量:为10,分页为10。
items:当前页面项目
添加文章
@admin_bp.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
    form = PostForm()
    if form.validate_on_submit():
        title = form.title.data
        body = form.body.data
        category = Category.query.get(form.category.data)
        post = Post(title=title, body=body, category=category)
        db.session.add(post)
        db.session.commit()
        flash('Post created.', 'success')
        return redirect(url_for('blog.show_post', post_id=post.id))
    return render_template('admin/new_post.html', form=form)
 
修改文章
@admin_bp.route('/post/<int:post_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_post(post_id):
    form = PostForm()
    post = Post.query.get_or_404(post_id)
    if form.validate_on_submit():
        post.title = form.title.data
        post.body = form.body.data
        post.category = Category.query.get(form.category.data)
        db.session.commit()
        flash('Post updated.', 'success')
        return redirect(url_for('blog.show_post', post_id=post.id))
    form.title.data = post.title
    form.body.data = post.body
    form.category.data = post.category_id
    return render_template('admin/edit_post.html', form=form)
edit_post视图的工作可以概括为:
首先从数据库中获取指定id的文章。如果是GET请求,使用文章的数据作为表单数据,然后渲染模板。
如果是POST请求,即用户单击了提交按钮,则根据表单的数据更新文章记录的数据。
和保存文章时的做法相反,通过把数据库字段的值分别赋给表单字段的数据,在渲染表单时,这些值会被填充到对应的input标签的value属性中,从而显示在输入框内。
需要注意,因为表单中的分类字段是存储分类记录的id值,所以这里使用post.category_id作为form.category.data的值。
 
删除文章
@admin_bp.route('/post/<int:post_id>/delete', methods=['POST'])
@login_required
def delete_post(post_id):
    post = Post.query.get_or_404(post_id)
    db.session.delete(post)
    db.session.commit()
    flash('Post deleted.', 'success')
    return redirect_back()
博客案例参考:Flask Web开发实战入门、进阶与原来解析
打赏
赞(0) 打赏
未经允许不得转载:同乐学堂 » Flask入门到精通-Day4

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

error: Sorry,暂时内容不可复制!