flask内容

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。

flask中虚拟环境的搭建(参考博客)

 1 sudo pip install virtualenv
 2 sudo pip install virtualenvwrapper
 3 
 4 # 1、创建目录用来存放虚拟环境
 5 mkdir
 6 $HOME/.virtualenvs
 7 
 8 # 2、打开~/.bashrc文件,并添加如下:
 9 export WORKON_HOME=$HOME/.virtualenvs
10 source /usr/local/bin/virtualenvwrapper.sh
11 
12 # 3、运行
13 source ~/.bashrc
14 
15 创建虚拟环境
16 mkvirtualenv 虚拟环境名称
17 例 :
18 mkvirtualenv py_flask
19 
20 mkvirtualenv -p python3 虚拟环境名称
21 例 :
22 mkvirtualenv -p python3 py3_flask
23 
24 进入虚拟环境
25 workon 虚拟环境名称
26 
27 例 :使用python2的虚拟环境
28 workon py_flask
29 
30 例 :使用python3的虚拟环境
31 workon py3_flask
32 
33 退出虚拟环境
34 deactivate
35 
36 rmvirtualenv 虚拟环境名称
37 
38 例 :删除虚拟环境py3_flask
39 
40 先退出:deactivate
41 再删除:rmvirtualenv py3_flask
42 
43 在虚拟环境中安装包
44 pip install 包名称
flask虚拟环境的搭建

 一,flask的基本使用:

 1 from flask import Flask
 2 
 3 app = Flask(__name__)
 4 
 5 
 6 @app.route('/')
 7 def hello_world():
 8     return 'Hello World!'
 9 
10 
11 if __name__ == '__main__':
12     app.run(debug=True)
flask的基本使用

 

二,基本的配置

 1 # default_config = ImmutableDict({
 2 #     'DEBUG': False,
 3 #     'TESTING': False,
 4 #     'PROPAGATE_EXCEPTIONS': None,
 5 #     'PRESERVE_CONTEXT_ON_EXCEPTION': None,
 6 #     'SECRET_KEY': None,
 7 #     'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
 8 #     'USE_X_SENDFILE': False,
 9 #     'LOGGER_NAME': None,
10 #     'SERVER_NAME': None,
11 #     'APPLICATION_ROOT': None,
12 #     'SESSION_COOKIE_NAME': 'session',
13 #     'SESSION_COOKIE_DOMAIN': None,
14 #     'SESSION_COOKIE_PATH': None,
15 #     'SESSION_COOKIE_HTTPONLY': True,
16 #     'SESSION_COOKIE_SECURE': False,
17 #     'MAX_CONTENT_LENGTH': None,
18 #     'SEND_FILE_MAX_AGE_DEFAULT': 12 * 60 * 60,  # 12 hours
19 #     'TRAP_BAD_REQUEST_ERRORS': False,
20 #     'TRAP_HTTP_EXCEPTIONS': False,
21 #     'PREFERRED_URL_SCHEME': 'http',
22 #     'JSON_AS_ASCII': True,
23 #     'JSON_SORT_KEYS': True,
24 #     'JSONIFY_PRETTYPRINT_REGULAR': True,
25 # })
26 
27 
28 
29 方式一
30  创建 Flask 类的对象,指向程序所在的包的名称
31 app = Flask(__name__)
32 
33 # 从配置文件中加载配置
34 app.config.from_pyfile('config.ini')
35 
36 方式二:
37 # 配置对象,里面定义需要给 APP 添加的一系列配置
38 class Config(object):
39     # DEBUG = True
40 
41 
42 # 创建 Flask 类的对象,指向程序所在的包的名称
43 app = Flask(__name__)
44 
45 # 从配置对象中加载配置
46 app.config.from_object(Config)
配置文件的方式

三,路由系统

1 DEFAULT_CONVERTERS = {
2     'default':          UnicodeConverter,
3     'string':           UnicodeConverter,
4     'any':              AnyConverter,
5     'path':             PathConverter,
6     'int':              IntegerConverter,
7     'float':            FloatConverter,
8     'uuid':             UUIDConverter,
9 }

路由关系的创建

 1 from flask import Flask
 2 from flask import request
 3 
 4 app = Flask(__name__)
 5 
 6 
 7 # 指定访问路径为 demo1
 8 @app.route('/demo1')
 9 def demo1():
10     return 'demo1'
11 
12 
13 # 路由传递的参数默认当做 string 处理,也可以指定参数的类型
14 @app.route('/user/<int:user_id>')
15 def user_info(user_id):
16     return 'hello %d' % user_id
17 
18 
19 @app.route('/demo2', methods=['GET', 'POST'])
20 def demo2():
21     # 直接从请求中取到请求方式并返回
22     return request.method
23 
24 
25 if __name__ == '__main__':
26     app.run(debug=True)
 1 from werkzeug.routing import BaseConverter
 2 from flask import Flask
 3 
 4 
 5 # 自定义正则转换器
 6 class RegexConverter(BaseConverter):
 7     def __init__(self, url_map, *args):
 8         super(RegexConverter, self).__init__(url_map)
 9         # 将接受的第1个参数当作匹配规则进行保存
10         self.regex = args[0]
11 
12 
13 app = Flask(__name__)
14 
15 # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
16 app.url_map.converters['re'] = RegexConverter
17 
18 
19 @app.route('/user/<re("[0-9]{3}"):user_id>')
20 def user_info(user_id):
21     return "user_id 为 %s" % user_id
22 
23 
24 if __name__ == '__main__':
25     app.run(debug=True)
自定义路由正则
 1 from werkzeug.routing import BaseConverter
 2 from flask import Flask
 3 
 4 
 5 # 自定义正则转换器
 6 class RegexConverter(BaseConverter):
 7     def __init__(self, url_map, *args):
 8         super(RegexConverter, self).__init__(url_map)
 9         # 将接受的第1个参数当作匹配规则进行保存
10         self.regex = args[0]
11 
12     def to_python(self, value):
13         return int(value)
14 
15 
16 app = Flask(__name__)
17 
18 # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
19 app.url_map.converters['re'] = RegexConverter
20 
21 
22 @app.route('/user/<re("[0-9]{3}"):user_id>')
23 def user_info(user_id):
24     print("user_id的类型为", type(user_id))
25     return "user_id 为 %s" % user_id
26 
27 
28 if __name__ == '__main__':
29     app.run(debug=True)
to_python方法
1 to_url:
2 在使用 url_for 去获取视图函数所对应的 url 的时候,会调用此方法对 url_for 后面传入的视图函数参数做进一步处理
3 具体可参见 Flask 的 app.py 中写的示例代码:ListConverter
to_url方法

视图的常用逻辑

不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,
如果是 JSON 需要指定 content-type:application/json
 1 from flask import Flask
 2 from flask import jsonify
 3 
 4 app = Flask(__name__)
 5 
 6 
 7 # 返回JSON
 8 @app.route('/demo4')
 9 def demo4():
10     json_dict = {
11         "user_id": 10,
12         "user_name": "laowang"
13     }
14     return jsonify(json_dict)
15 
16 
17 if __name__ == '__main__':
18     app.run(debug=True)
19 
20 
21 # 不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,
22 # 如果是 JSON 需要指定 content-type:application/json
数据的返回

重定向

重定向到指定的网址

 1 from flask import Flask
 2 from flask import redirect
 3 
 4 app = Flask(__name__)
 5 
 6 
 7 @app.route('/demo5')
 8 def demo5():
 9     return redirect('http://www.itheima.com')
10 
11 
12 if __name__ == '__main__':
13     app.run(debug=True)

重定向到自己写的函数中

1 @app.route('/demo1')
2 def demo1():
3     return 'demo1'
4 
5 @app.route('/demo5')
6 def demo5():
7     return redirect(url_for('demo1'))

重定向到带有参数的路由函数中

 1 # 路由传递参数
 2 @app.route('/user/<int:user_id>')
 3 def user_info(user_id):
 4     return 'hello %d' % user_id
 5 
 6 
 7 # 重定向
 8 @app.route('/demo5')
 9 def demo5():
10     # 使用 url_for 生成指定视图函数所对应的 url
11     return redirect(url_for('user_info', user_id=100))

  自定义状态码

1 @app.route('/demo6')
2 def demo6():
3     return '状态码为 666', 666

异常的捕获

 1 from flask import Flask
 2 from flask import abort
 3 
 4 app = Flask(__name__)
 5 
 6 
 7 @app.route('/')
 8 def hello_world():
 9     return 'Hello World!'
10 
11 
12 @app.route("/demo1")
13 def demo1():
14     # 主动http状态码
15     abort(404)
16     return "demo1"
17 
18 
19 # 使用装饰器来捕获异常指定的状态码和异常
20 @app.errorhandler(404)
21 def page_not_fund(error):
22     print(error)
23     return "页面不存在"
24 
25 
26 @app.route("/demo2")
27 def div_demo2():
28     a = 5
29     b = 0
30     return a / b
31 
32 
33 # 使用错误捕获来捕获除数不能为0的的错误
34 @app.errorhandler(ZeroDivisionError)
35 def Zero_Division_Error(error):
36     print(error)
37     return "除数不能为0"
38 
39 
40 # 第二种捕获异常的方式
41 # def page_not_found(error):
42 #     return '你访问的页面不存在', 404
43 # app.error_handler_spec[None][404] = page_not_found
44 
45 
46 
47 if __name__ == '__main__':
48     app.run(debug=True)
View Code

  注册一个处理程序错误的装饰器,当程序抛出指定错误状态码的时候会调用装饰器所装饰的方法(除了捕获异常的状态码之外还可以捕获指定的异常)

flask中的请求钩子

 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 
 4 from flask import Flask
 5 
 6 app = Flask(__name__)
 7 
 8 
 9 @app.before_first_request
10 def before_first_request():
11     print("before_first_request")
12 
13 
14 @app.before_request
15 def before_request():
16     print("before_request")
17 
18 
19 @app.after_request
20 def after_request(response):
21     print("response", response)
22     print("after_request")
23     return response
24 
25 
26 # 在请求之后可以被执行,如果有异常会将此异常传入到这个函数来做处理
27 @app.teardown_request
28 def teardown_request(error):
29     print(error)
30     print("teardown_request")
31 
32 
33 @app.route('/')
34 def index():
35     print("index", index)
36     return 'index'
37 
38 
39 if __name__ == '__main__':
40     app.run(debug=True)
View Code
before_first_request(在处理第一个请求前执行,后续的执行过程就不会再执行了)
before_request(每次发起请求前都会执行,如果在某个修饰函数中返回一个响应,视图函数将不再被调用)
after_request

没有抛出异常,则在每次请求后会执行
接收一个参数:视图函数做出的响应;
在此函数中可以对视图函数做出的响应做最后一步的处理;
需要将参数中的响应在此函数中返回

teardown_request

每次请求之后都会执行;
接收一个参数:如果抛出异常,则参数会捕捉到这个异常;


 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 
 4 from flask import Flask,request
 5 from werkzeug.serving import run_simple
 6 
 7 app = Flask(__name__)
 8 
 9 
10 @app.route('/')
11 def hello_world():
12     return 'Hello World!'
13 
14 @app.route('/index', methods=["POST",])
15 def index():
16     print(request.method)
17     return 'index index!'
18 
19 # rule 视图函数和酷游关系的映射关系
20 # map rule的集合
21 # BaseConverter匹配路由匹配的规则
22 # MapAdapter协调以上的路由匹配的工作
23 
24 
25 if __name__ == '__main__':
26     print(app.url_map)
27     app.run(debug=True)
装饰器路由功能的实现

Werkzeug库的 routing 模块负责实现 URL 解析。不同的 URL 对应不同的视图函数,routing模块会对请求信息的URL进行解析,匹配到URL对应的视图函数,执行该函数以此生成一个响应信息。

routing模块内部有:

    • Rule类
      • 用来构造不同的URL模式的对象,路由URL规则
    • Map类
      • 存储所有的URL规则和一些配置参数
    • BaseConverter的子类
      • 负责定义匹配规则
    • MapAdapter类
      • 负责协调Rule做具体的匹配的工作

请求上下文(request context)

 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 
 4 
 5 from flask import Flask
 6 from flask import request
 7 
 8 app = Flask(__name__)
 9 
10 
11 @app.route('/index', methods=["GET", "POST"])
12 def index():
13     return 'Hello World!'
14 
15 
16 @app.route("/args", methods=["GET", "POST"])
17 def args():
18     # get方式地址栏传递参数
19     print(request.form.get("name"))
20     print(request.form.get("age"))
21     # post方式请求体中传递参数
22     print(request.args.get("name"))
23     print(request.args.get("age"))
24     return "success"
25 
26 
27 @app.route("/file", methods=["POST"])
28 def up_load_file():
29     print(request.method)
30     pic = request.files.get("pic")
31     pic.save("./static/aaaa.png")
32     return "success"
33 
34 
35 if __name__ == '__main__':
36     app.run(debug=True)
request的使用

request是flask中代表当前请求的request对象,是一个全局的请求上下文的一个变量(可以理解成为一个全局变量,在视图函数中可以直接使用,可以取到当前请求)。

 备注:在地址栏中请求数据的方式可以用args的方式去在request中取值,如果在form表单中的数据需要在form中取值。

cookie的设置

 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 
 4 from flask import Flask
 5 from flask import request
 6 from flask import make_response
 7 
 8 app = Flask(__name__)
 9 
10 
11 # 获取cookies
12 @app.route('/index')
13 def index():
14     username = request.cookies.get("username")
15     user_id = request.cookies.get("user_id")
16     return '%s---%s' % (username, user_id)
17 
18 
19 # 设置cookies
20 @app.route("/login")
21 def login():
22     response = make_response("success")
23     response.set_cookie("username", "xiaoimng", max_age=3600)
24     response.set_cookie("user_id", "1", max_age=3600)
25     return response
26 
27 
28 # 删除cookies
29 @app.route("/logout")
30 def logout():
31 
32     response = make_response("删除cookies成功")
33     response.delete_cookie("user_id")
34     response.delete_cookie("username")
35     return response
36 
37 
38 if __name__ == '__main__':
39     app.run(debug=True)
cookie的设置

备注:

1,cookie的设置是在response中进行设置,在request中取值;

2,http是一种无状态的协议,浏览器在请求服务器的时候是无状态的,

无状态的原因是:

浏览器与服务器通过socket进行通信,服务器会将请求结果返回给浏览器,请求完毕后服务器都会将通信套接字关闭,并且服务器在关闭套接字之后就会销毁请求的页面的对象;

有时需要保持浏览器的状态,比如用户的登录状态,和浏览过的信息等;

无状态协议

1,协议对事物的处理没有记忆的功能;

2,对于同一个url请求没有上下文的关系;

3,每次执行的结果都是独立的,它执行的结果和情况与上前面的请求和之后的请求没有直接的关系,它不会受前面的请求应答的影响,也不会对后面的请求应答产生影响;

4,服务器没有保持客户端的状态,客户端每次需要自己将状态带到服务区端;

实现状态保持有两种方式;

1,在客户端设置cookie,在每次发送请求的时候将cookie带给服务器端;

2,在服务器端设置session,每次客户福安发送来请求之后,将客户端的cookie与session做做对比;(所有说session是依赖于cookie的,cookie可以单独存在session不可以独立存在);

 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 from datetime import timedelta
 4 from flask import Flask
 5 from flask import session
 6 
 7 app = Flask(__name__)
 8 app.config["SECRET_KEY"] = "abcdefg"
 9 
10 
11 # app.secret_key["SECRET_KEY"] = "abcsefght"
12 
13 @app.route('/index')
14 def index():
15     user_name = session.get("user_name")
16     user_id = session.get("user_id")
17     return "%s---%s" % (user_name, user_id)
18 
19 
20 @app.route("/login")
21 def login():
22     session.permanent = True
23     app.permanent_session_lifetime = timedelta(second=10)
24     session["user_name"] = "xiaomingh"
25     session["user_id"] = "1"
26     return "session设置成功"
27 
28 
29 @app.route("/logout")
30 def logout():
31     session.pop("user_name", None)
32     session.pop("user_id", None)
33     return "session删除删除成功"
34 
35 
36 if __name__ == '__main__':
37     app.run(debug=True)
session的设置

 

思考:在视图函数中,如何取到当前请求的相关数据?比如:请求地址,请求方式,cookie等等

在 flask 中,可以直接在视图函数中使用 request 这个对象进行获取相关数据,而 request 就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session

    • request
      • 封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。
    • session
      • 用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。

应用上下文(application context)

它的字面意思是 应用上下文,但它不是一直存在的,它只是request context 中的一个对 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而生,随 request 而灭的。

应用上下文对象有:current_app,g

current_app

应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

    • 应用的启动脚本是哪个文件,启动时指定了哪些参数
    • 加载了哪些配置文件,导入了哪些配置
    • 连了哪个数据库
    • 有哪些public的工具类、常量
    • 应用跑再哪个机器上,IP多少,内存多大
current_app.name
current_app.test_value='value'

g变量

g 作为 flask 程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别

 





flask_script
 1 #! /usr/bin/env python
 2 # *-* coding: utf-8 *-*
 3 
 4 
 5 from flask import Flask
 6 # 请求上下文的变量
 7 from flask import request, make_response
 8 # 运用上下文的变量
 9 from flask_script import Manager
10 from flask import current_app
11 from flask import g
12 
13 app = Flask(__name__)
14 app.debug = True
15 manager = Manager(app)
16 
17 
18 @app.route('/')
19 def hello_world():
20     # 类似于一个全局变量的东西
21     print(current_app.config.get("DEBUG"))
22     return 'Hello World!'
23 
24 
25 if __name__ == '__main__':
26     manager.run()
27     # app.run(debug=True)
View Code

通过使用Flask-Script扩展,我们可以在Flask服务器启动的时候,通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参,比如我们可以通过:

python hello.py runserver -host ip地址


原文地址:https://www.cnblogs.com/cerofang/p/9200949.html