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中虚拟环境的搭建(参考博客)

 sudo pip install virtualenv
sudo pip install virtualenvwrapper # 1、创建目录用来存放虚拟环境
mkdir
$HOME/.virtualenvs # 2、打开~/.bashrc文件,并添加如下:
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh # 3、运行
source ~/.bashrc 创建虚拟环境
mkvirtualenv 虚拟环境名称
例 :
mkvirtualenv py_flask mkvirtualenv -p python3 虚拟环境名称
例 :
mkvirtualenv -p python3 py3_flask 进入虚拟环境
workon 虚拟环境名称 例 :使用python2的虚拟环境
workon py_flask 例 :使用python3的虚拟环境
workon py3_flask 退出虚拟环境
deactivate rmvirtualenv 虚拟环境名称 例 :删除虚拟环境py3_flask 先退出:deactivate
再删除:rmvirtualenv py3_flask 在虚拟环境中安装包
pip install 包名称

flask虚拟环境的搭建

一,flask的基本使用:

 from flask import Flask

 app = Flask(__name__)

 @app.route('/')
def hello_world():
return 'Hello World!' if __name__ == '__main__':
app.run(debug=True)

flask的基本使用

二,基本的配置

 # default_config = ImmutableDict({
# 'DEBUG': False,
# 'TESTING': False,
# 'PROPAGATE_EXCEPTIONS': None,
# 'PRESERVE_CONTEXT_ON_EXCEPTION': None,
# 'SECRET_KEY': None,
# 'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
# 'USE_X_SENDFILE': False,
# 'LOGGER_NAME': None,
# 'SERVER_NAME': None,
# 'APPLICATION_ROOT': None,
# 'SESSION_COOKIE_NAME': 'session',
# 'SESSION_COOKIE_DOMAIN': None,
# 'SESSION_COOKIE_PATH': None,
# 'SESSION_COOKIE_HTTPONLY': True,
# 'SESSION_COOKIE_SECURE': False,
# 'MAX_CONTENT_LENGTH': None,
# 'SEND_FILE_MAX_AGE_DEFAULT': 12 * 60 * 60, # 12 hours
# 'TRAP_BAD_REQUEST_ERRORS': False,
# 'TRAP_HTTP_EXCEPTIONS': False,
# 'PREFERRED_URL_SCHEME': 'http',
# 'JSON_AS_ASCII': True,
# 'JSON_SORT_KEYS': True,
# 'JSONIFY_PRETTYPRINT_REGULAR': True,
# }) 方式一
创建 Flask 类的对象,指向程序所在的包的名称
app = Flask(__name__) # 从配置文件中加载配置
app.config.from_pyfile('config.ini') 方式二:
# 配置对象,里面定义需要给 APP 添加的一系列配置
class Config(object):
# DEBUG = True # 创建 Flask 类的对象,指向程序所在的包的名称
app = Flask(__name__) # 从配置对象中加载配置
app.config.from_object(Config)

配置文件的方式

三,路由系统

 DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}

路由关系的创建

 from flask import Flask
from flask import request app = Flask(__name__) # 指定访问路径为 demo1
@app.route('/demo1')
def demo1():
return 'demo1' # 路由传递的参数默认当做 string 处理,也可以指定参数的类型
@app.route('/user/<int:user_id>')
def user_info(user_id):
return 'hello %d' % user_id @app.route('/demo2', methods=['GET', 'POST'])
def demo2():
# 直接从请求中取到请求方式并返回
return request.method if __name__ == '__main__':
app.run(debug=True)
 from werkzeug.routing import BaseConverter
from flask import Flask # 自定义正则转换器
class RegexConverter(BaseConverter):
def __init__(self, url_map, *args):
super(RegexConverter, self).__init__(url_map)
# 将接受的第1个参数当作匹配规则进行保存
self.regex = args[0] app = Flask(__name__) # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
app.url_map.converters['re'] = RegexConverter @app.route('/user/<re("[0-9]{3}"):user_id>')
def user_info(user_id):
return "user_id 为 %s" % user_id if __name__ == '__main__':
app.run(debug=True)

自定义路由正则

 from werkzeug.routing import BaseConverter
from flask import Flask # 自定义正则转换器
class RegexConverter(BaseConverter):
def __init__(self, url_map, *args):
super(RegexConverter, self).__init__(url_map)
# 将接受的第1个参数当作匹配规则进行保存
self.regex = args[0] def to_python(self, value):
return int(value) app = Flask(__name__) # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
app.url_map.converters['re'] = RegexConverter @app.route('/user/<re("[0-9]{3}"):user_id>')
def user_info(user_id):
print("user_id的类型为", type(user_id))
return "user_id 为 %s" % user_id if __name__ == '__main__':
app.run(debug=True)

to_python方法

 to_url:
在使用 url_for 去获取视图函数所对应的 url 的时候,会调用此方法对 url_for 后面传入的视图函数参数做进一步处理
具体可参见 Flask 的 app.py 中写的示例代码:ListConverter

to_url方法

视图的常用逻辑

不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,
如果是 JSON 需要指定 content-type:application/json
 from flask import Flask
from flask import jsonify app = Flask(__name__) # 返回JSON
@app.route('/demo4')
def demo4():
json_dict = {
"user_id": 10,
"user_name": "laowang"
}
return jsonify(json_dict) if __name__ == '__main__':
app.run(debug=True) # 不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,
# 如果是 JSON 需要指定 content-type:application/json

数据的返回

重定向

重定向到指定的网址

 from flask import Flask
from flask import redirect app = Flask(__name__) @app.route('/demo5')
def demo5():
return redirect('http://www.itheima.com') if __name__ == '__main__':
app.run(debug=True)

重定向到自己写的函数中

 @app.route('/demo1')
def demo1():
return 'demo1' @app.route('/demo5')
def demo5():
return redirect(url_for('demo1'))

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

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

  自定义状态码

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

异常的捕获

 from flask import Flask
from flask import abort app = Flask(__name__) @app.route('/')
def hello_world():
return 'Hello World!' @app.route("/demo1")
def demo1():
# 主动http状态码
abort(404)
return "demo1" # 使用装饰器来捕获异常指定的状态码和异常
@app.errorhandler(404)
def page_not_fund(error):
print(error)
return "页面不存在" @app.route("/demo2")
def div_demo2():
a = 5
b = 0
return a / b # 使用错误捕获来捕获除数不能为0的的错误
@app.errorhandler(ZeroDivisionError)
def Zero_Division_Error(error):
print(error)
return "除数不能为0" # 第二种捕获异常的方式
# def page_not_found(error):
# return '你访问的页面不存在', 404
# app.error_handler_spec[None][404] = page_not_found if __name__ == '__main__':
app.run(debug=True)

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

flask中的请求钩子

 #! /usr/bin/env python
# *-* coding: utf-8 *-* from flask import Flask app = Flask(__name__) @app.before_first_request
def before_first_request():
print("before_first_request") @app.before_request
def before_request():
print("before_request") @app.after_request
def after_request(response):
print("response", response)
print("after_request")
return response # 在请求之后可以被执行,如果有异常会将此异常传入到这个函数来做处理
@app.teardown_request
def teardown_request(error):
print(error)
print("teardown_request") @app.route('/')
def index():
print("index", index)
return 'index' if __name__ == '__main__':
app.run(debug=True)
before_first_request(在处理第一个请求前执行,后续的执行过程就不会再执行了)
before_request(每次发起请求前都会执行,如果在某个修饰函数中返回一个响应,视图函数将不再被调用)
after_request

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

teardown_request

每次请求之后都会执行;
接收一个参数:如果抛出异常,则参数会捕捉到这个异常;
 #! /usr/bin/env python
# *-* coding: utf-8 *-* from flask import Flask,request
from werkzeug.serving import run_simple app = Flask(__name__) @app.route('/')
def hello_world():
return 'Hello World!' @app.route('/index', methods=["POST",])
def index():
print(request.method)
return 'index index!' # rule 视图函数和酷游关系的映射关系
# map rule的集合
# BaseConverter匹配路由匹配的规则
# MapAdapter协调以上的路由匹配的工作 if __name__ == '__main__':
print(app.url_map)
app.run(debug=True)

装饰器路由功能的实现

flask内容

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

routing模块内部有:

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

请求上下文(request context)

 #! /usr/bin/env python
# *-* coding: utf-8 *-* from flask import Flask
from flask import request app = Flask(__name__) @app.route('/index', methods=["GET", "POST"])
def index():
return 'Hello World!' @app.route("/args", methods=["GET", "POST"])
def args():
# get方式地址栏传递参数
print(request.form.get("name"))
print(request.form.get("age"))
# post方式请求体中传递参数
print(request.args.get("name"))
print(request.args.get("age"))
return "success" @app.route("/file", methods=["POST"])
def up_load_file():
print(request.method)
pic = request.files.get("pic")
pic.save("./static/aaaa.png")
return "success" if __name__ == '__main__':
app.run(debug=True)

request的使用

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

flask内容

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

cookie的设置

 #! /usr/bin/env python
# *-* coding: utf-8 *-* from flask import Flask
from flask import request
from flask import make_response app = Flask(__name__) # 获取cookies
@app.route('/index')
def index():
username = request.cookies.get("username")
user_id = request.cookies.get("user_id")
return '%s---%s' % (username, user_id) # 设置cookies
@app.route("/login")
def login():
response = make_response("success")
response.set_cookie("username", "xiaoimng", max_age=3600)
response.set_cookie("user_id", "", max_age=3600)
return response # 删除cookies
@app.route("/logout")
def logout(): response = make_response("删除cookies成功")
response.delete_cookie("user_id")
response.delete_cookie("username")
return response if __name__ == '__main__':
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不可以独立存在);

 #! /usr/bin/env python
# *-* coding: utf-8 *-*
from datetime import timedelta
from flask import Flask
from flask import session app = Flask(__name__)
app.config["SECRET_KEY"] = "abcdefg" # app.secret_key["SECRET_KEY"] = "abcsefght" @app.route('/index')
def index():
user_name = session.get("user_name")
user_id = session.get("user_id")
return "%s---%s" % (user_name, user_id) @app.route("/login")
def login():
session.permanent = True
app.permanent_session_lifetime = timedelta(second=10)
session["user_name"] = "xiaomingh"
session["user_id"] = ""
return "session设置成功" @app.route("/logout")
def logout():
session.pop("user_name", None)
session.pop("user_id", None)
return "session删除删除成功" if __name__ == '__main__':
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
 #! /usr/bin/env python
# *-* coding: utf-8 *-* from flask import Flask
# 请求上下文的变量
from flask import request, make_response
# 运用上下文的变量
from flask_script import Manager
from flask import current_app
from flask import g app = Flask(__name__)
app.debug = True
manager = Manager(app) @app.route('/')
def hello_world():
# 类似于一个全局变量的东西
print(current_app.config.get("DEBUG"))
return 'Hello World!' if __name__ == '__main__':
manager.run()
# app.run(debug=True)

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

python hello.py runserver -host ip地址


上一篇:javascript 分离全局变量


下一篇:jQuery中attr和prop方法的区别说明