Flask 快速入门

一、Flask 简介

Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权。

Flask也被称为 “microframework” ,因为它使用简单的核心,并且被设计为可扩展形式。故而没有提供一些重要的功能,例如数据库和用户认证,所以开发者可以自由选择最适合程序的包,或者按照需求自行开发。

社区成员开发了大量的不同用途的扩展,如果这还不能满足需求,你还可以使用所有Python标准包或代码库。

image.png

二、Flask 安装

一般安装python后会自带pip工具,方便下载安装python各类库,如果没有自行百度。

pip install flask

三、最简单Flask应用

# app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run() # 启动服务器

写完后直接用python运行,默认监听本地5000端口,访问http://127.0.0.1:5000/就能看到Hello World!

四、初始化应用

所有Flask程序都必须创建一个程序实例,所有功能都是围绕这个实例进行的,接收自客户端的所有请求都将转交到这个对象处理。程序实例是Flask类的对象,经常使用下述代码创建一个实例:

from flask import Flask
app = Flask(__name__)

五、路由和视图函数

  • 路由

客户端(如Web浏览器)把请求发送给Web服务器,Web服务器再把请求发送给Flask程序实例,程序实例需要知道对每个URL请求运行哪些代码,所以保存了一个URL到Python函数的映射关系。处理URL和函数之间关系的程序称为路由

  • 视图函数

前面最简单的Flask应用中定义了一个函数hello_world(),该函数被注册为程序根地址(/)的处理程序,也就是访问http://127.0.0.1:5000/时,会触发服务器执行hello_world()函数,函数的返回值成为响应,是客户端接收到的内容,如果客户端是Web浏览器,响应就是返回给用户的HTML文档。
hello_world()这样的用于处理请求的函数称为视图函数。视图函数可以返回简单的HTML字符串,也可以返回一个完整的HTML文档(这里就要用到Jinja2模板引擎啦)。

  • 注册一个视图函数最常用的方法就是用app.route():
@app.route("/")
def hello_world():
    pass
  • 限制路由的请求方法
@app.route("/", methods=["GET"])
def hello_world():
    pass

这样,要是客户端以POST的方式请求该路由,就会返回“405 Method Not Allowed”

  • 向路由函数传参
    有的时候我们需要通过url获取有用的信息,比如说知道来访者的姓名,以便在返回的欢迎语中加入他的名字。
@app.route("/hello/<string:name>")
def hello(name):
   return "hello, " + name

上例中,在定义该路由的访问路径里加了一个<string:name>,并增加了一个同名函数参数。
更一般的情况是<type:param>,其中type是类型,常用的有string、int,param就是参数名,它会传递到路由函数的同名参数里。

六、启动服务器

当Flask应用被初始化且视图函数定义好之后,就可以启动Flask应用啦。

if __name__ == "__main__":
    app.run() # 默认监听本地5000端口
    # app.run(port=8080) 监听8080端口

七、请求 - 响应循环

说到请求,必须要先介绍一下上下文

  • 上下文(Context)

上下文,在阅读文章时经常提到,意思是语境、语意。在程序设计中,上下文的概念也是类似的,你可以这么理解:
通俗地讲,每一段代码都有许多外部变量,比如一个函数需要传入若干个必填的参数才能够运行,那些参数就是上下文的一部分,意味着该函数无法独立运行,需要上下文的支持。而许多函数都是需要各种参数才能运行的,这些参数组成的集合就称为上下文。

  • Flask中的上下文

变量名 上下文 说明
current_app 程序上下文 当前激活程序的程序实例
g 程序上下文 上下文全局变量
request 请求上下文 请求对象,封装了客户端发出的HTTP请求中的内容
session 请求上下文 用户会话,用户储存同一个客户端在多个请求间需要“记住”的信息
  • 请求上下文

请求上下文变量是在视图函数被触发时传入的一个HTTP请求对象,储存了所有客户端发送过来的数据,因此该变量只有在视图函数中才能访问。如果难以理解,你只需要记住request变量只有在视图函数中才能访问
我们可以通过以下方式引入请求上下文变量:

from flask import request
  • 请求上下文变量常用的访问操作有:

    request.args 获取所有GET请求参数
    request.form 获取所有form-data、x-www-form-urlencoded类型的请求参数
    request.json 获取所有json类型的请求参数
    request.method 获取请求方法
    request.headers 获取请求头

  • 请求钩子

    • 什么是钩子(Hook)?
      打个比方,鱼钩是用来钓鱼的,一旦鱼咬了钩,钩子就一直钩住鱼了,任凭鱼在水里怎么游,也逃不出鱼钩的控制。在程序设计里,钩子就是一个事件,钩住了某段代码,任凭这段代码这么运行,都逃不过我的钩子事件。

    • Flask里的请求钩子

      钩子 说明
      before_first_request 注册一个函数,在处理第一个请求之前运行
      before_request 注册一个函数,在每次请求之前运行
      after_request 注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行
      teardown_request 注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行
    • 用法

    from flask import request
    
    @app.before_request
    def app_before_request():
        print("HTTP {}  {}".format(request.method, request.url))
    

    这样在每次请求时都会输出请求方式和请求url,但其实钩子函数的作用远不止这些。

  • 响应

    通常,每个视图函数都有返回值,而最简单的就是一串字符串了,Flask默认返回的类型是text/html,状态码为200。状态码很重要,如果需要修改,我们可以这样做:

    @app.route("/")
    def hello_word():
        return "Not Found", 404
    

    当然,如果要自定义响应,最好还是引入make_response函数,该函数接受一个bytes对象(二进制数据)或者字符串作为响应主体,并返回一个响应对象response,通过这个对象我们可以自定义该响应的头部,比如修改响应头部的Content-Type和Content-Disposition来告诉客户端这个文件是需要被下载的,并且将From设置为Ncuhome来告诉客户端该文件来自家园工作室。

    @app.route("/download")
    def download():
      response = make_response(open("lesson.md", "rb").read())
      response.headers["From"] = "Ncuhome"
      response.headers["Content-Type"] = "application/octet-stream; charset=utf-8;"
      response.headers["Content-Disposition"] = "attachment;filename=lesson.md"
      return response
    
  • 快速构建一个json格式的响应

    前后端交互时,一般都是使用JSON格式数据进行交互

    from flask import jsonify
    @app.route('/hello', methods=['GET'])
    def user(user_id):
        if not user_id == 1:
            abort(404)
    
        return jsonify({
            "status": 1,
            "data": {
                "username": "ncuhome",
                "desc": "Hello, Ncuhomer!",
            },
            "message": "获取成功"
        })
    
  • 其他一些响应

    • 重定向
    from flask import redirect
    @app.route("/ncuos")
    def ncuos():
        return redirect("https://www.ncuos.com/")
    
    • 重定向到某个路由
    from flask import url_for
    @app.route("/redirect_to_hello")
    def redirect():
        return redirect(url_for("hello"))
    
    @app.route("/hello")
    def hello():
        return "Hello, Ncuhomer!"
    
    • 返回HTTP状态码
    from flask import abort
    @app.route("/user/<int:user_id>")
    def get_user(user_id):
        abort(404)
    

Jinja2 模板引擎

前面提到了Jinja2,它的作用其实是为了方便构造HTML文档、以及其他的一些文档内容(邮件等)。

  • 响应返回完整HTML
    简单举个栗子吧
    模板文件 ./template/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ncuhome Demo</title>
    </head>
    <body>
        Hello, {{ name }}
    </body>
    </html>
    
    其中name就是我们需要填补的,它用花括号{{ }}括起来了。
    填补name并返回完整HTML:
     from flask import render_template
     @app.route("/hello/<string:name>")
     def hello(name):
         return render_template("index.html", name=name)
    
  • 模板中的for循环
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Ncuhome Demo</title>
    </head>
    <body>
      {% for user in users %}
      {{ loop.index }}: {{ user }} <br>
      {% endfor %}
    </body>
    </html>
    
     from flask import render_template
     @app.route("/users")
     def hello(name):
         users = ["Amy", "David", "Sam"]
         return render_template("index.html", users=users)
    
  • 模板中的if
    if和for类似,都拥有一个作用域,用法也一样。
    {% if name %}
       {{ name }}
    {% endif %}
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350