flask框架

文章目录

  • Flask框架
      • 1.框架介绍
      • 2. 基本使用
        • 环境安装
        • 在pycharm中新建flask项目
        • 新建一个helloflask.py文件
        • 第二种运行文件的方式
        • 第三中运行文件的方式
        • 路由
          • 1)定义路由
          • 2)路由变量
          • 3)路由转换器
          • 4)自定义路由转换器
        • 请求
        • 响应
          • 1)访问静态资源
          • 2)自定义响应对象
          • 3)返回json
          • 4)重定向
          • 5)响应状态码
        • 状态保持
          • 1)cookie
          • 2)session
        • 异常处理
      • 3.高级处理
        • 请求钩子
        • 蓝图
          • 1)基本使用
            • 代码示例
          • 2)使用细节
            • 代码示例
        • 上下文
          • 代码示例
        • 综合认证
          • 1)统一处理
            • 代码示例
          • 2)访问限制
        • 应用配置
          • 1)加载配置
          • 2)切换配置
            • 定义工厂函数
            • 动态创建应用
          • 加载隐私配置
  • flask-restful扩展
      • 1.视图
        • 基本使用
        • 类视图装饰器
        • 蓝图和类视图
      • 2.请求
        • 请求解析
        • 常用参数
      • 3.响应
        • 序列化
        • 自定义JSON
  • flask-sqlalchemy扩展
      • 1.基本使用
        • 扩展介绍
          • flask-sqlalchemy
          • orm优缺点
          • 环境安装
        • 组件初始化
          • 基本配置
          • 两种初始化方式
        • 构建模型类
          • orm映射关系
          • 常用的字段类型
          • 常用的字段选项
      • 2.数据操作
        • 增加数据
        • 查询数据
        • 更新数据
          • 先查询,再更新
          • 基于过滤条件的更新
        • 删除数据
      • 3.高级机制
        • 刷新数据
        • 多表查询
          • 外键关联查询
            • 数据关联
            • 关联查询
          • 关系属性
            • 基本使用
            • 反向引用
            • 动态查询
          • 连接查询
        • Session机制
          • 生命周期
          • session和事务
      • 4.sqlalchemy单体使用
        • 构建模型类
        • 构建session
        • 封装session
        • 关系属性和连接查询
        • 执行原生sql

Flask框架

1.框架介绍

	Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言编写的 **轻量级Web开发框架** ,其本身相当于一个内核,主要实现路**由分发和模板渲染功能**。

Flask中常用的扩展包:

  • Flask-SQLalchemy:ORM操作数据库;
  • Flask-RESTful:开发REST API的工具;
  • Flask-Session:Session存储;
  • Flask-Migrate:管理迁移数据库;
  • Flask-Caching:缓存;
  • Flask-WTF:表单;
  • Flask-Mail:邮件;
  • Flask-Login:认证用户状态;
  • Flask-OpenID:认证;
  • Flask-Admin:简单而可扩展的管理接口的框架
  • Flask-Bable:提供国际化和本地化支持,翻译;
  • Flask-Bootstrap:集成前端Twitter Bootstrap框架;
  • Flask-Moment:本地化日期和时间;

2. 基本使用

环境安装
mkvirtualenv flask_env -p python3 #创建名为flask_env的虚拟环境,使用python3解释器
pip install flask==1.0.3 #安装版本为1.0.3的flask包
在pycharm中新建flask项目

flask框架_第1张图片
flask框架_第2张图片
flask框架_第3张图片
flask框架_第4张图片

新建一个helloflask.py文件
from flask import Flask # 导入flask包
app = Flask(__name__) #创建flask对象,接收一个参数__name__,它会指向程序所在的包
@app.route('/') #定义路由
def index(): #视图
    return 'hello flask'
if __name__=='__main__':
    app.run() #运行程序
# app.run()中可以添加参数
# host: 绑定的ip(域名)  0.0.0.0
# port: 监听的端口号
# debug: 是否开启调试模式  1> 可以在网页上显示python错误 2> 更新代码后测试服务器自动重启
#app.run(host='0.0.0.0', port=8000, debug=True)

运行结果:

/home/ubuntu/.virtualenvs/flask_env/bin/python /home/ubuntu/PycharmProjects/flask2/helloflask.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Serving Flask app "helloflask" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
第二种运行文件的方式
  • flask1.0开始, 类似Django, 通过终端执行封装的脚本命令flask run来运行应用, 不再需要调用app.run()
  • 新的形式更加有利于 灵活修改环境配置
export FLASK_APP=xx.py #指定flask应用所在的文件路径
export FLASK_ENV=development #设置项目的环境,默认是生产环境
flask run -h 0.0.0.0 -p 8000 #启动测试服务器并接收请求
  • 在ubuntu中可以通过命令查看和修改环境变量
# 获取环境变量
export  # 查看所有环境变量
echo $环境变量   # 查看指定的环境变量

# 设置环境变量
export 环境变量名=值  # 给本次会话设置环境变量, 一旦终端关闭, 环境变量会清空
# 将环境变量写入配置文件(.bashrc/.bash_profile), 重新打开终端时再次加载环境变量
第三中运行文件的方式

flask框架_第5张图片
flask框架_第6张图片
flask框架_第7张图片
flask框架_第8张图片

路由
1)定义路由
  • 路由对应的URL必须以 / 开头
  • app.route()中可以使用methods方法,作用是指定路由支持的请求方式
  • 可以使用app.url_map命令获取所有路由规则
    • 路由规则中主要包含url资源段rule,支持的请求方式methods,视图函数标记endpoint三部分
from flask import Flask
app=Flask(__name__)
@app.route('/hello',methods=['get','post'])
def index():
    return 'index'
if __name__=='__main__':
    print(app.url_map)
    # 获取路由信息
    print('-----------------------------------')
    for rule in app.url_map.iter_rules():
        print(rule.rule, rule.methods, rule.endpoint)
    # 具体的获取每条路由信息中的项
    app.run(debug=True)

运行结果:

Map([<Rule '/hello' (POST, OPTIONS, GET, HEAD) -> index>,
 <Rule '/static/' (OPTIONS, GET, HEAD) -> static>])
-----------------------------------
/hello {
   'POST', 'OPTIONS', 'GET', 'HEAD'} index
/static/<path:filename> {
   'OPTIONS', 'GET', 'HEAD'} static

网页效果:
flask框架_第9张图片

2)路由变量
  • 用于传递url路径参数,实现动态url
  • 格式:/路径/<路由变量>
from flask import Flask
app=Flask(__name__)
@app.route('/user/')
def index(userid):
    print(userid)
    return 'index'
if __name__=='__main__':
    app.run(debug=True)

使用postment发送get请求:http://127.0.0.1:5000/user/18240118472
运行结果:

18240118472
127.0.0.1 - - [17/Mar/2020 19:49:30] "GET /user/18240118472 HTTP/1.1" 200 -
3)路由转换器
  • 作用是对url传递对的参数进行格式校验,类似django设置url时的正则表达式参数
  • 格式:/路径/<转换器名:路由变量>
  • 所有路由转换器都继承自BaseConverter类
from flask import Flask
app = Flask(__name__)
@app.route('/user/')
def index(userid):
    print(userid)
    return 'index'
if __name__=='__main__':
    app.run()

使用postment分别发送get请求:http://127.0.0.1:5000/user/18240
http://127.0.0.1:5000/user/18240a
运行结果分别为:

18240
127.0.0.1 - - [17/Mar/2020 20:03:42] "GET /user/18240 HTTP/1.1" 200 -

127.0.0.1 - - [17/Mar/2020 20:05:00] "GET /user/18240a HTTP/1.1" 404 -

4)自定义路由转换器
  • 路由转换器可以由开发者自定义,自定义路由转换器的步骤
    • 定义路由转换器类,继承BaseConverter类
    • 设置regex属性(正则匹配规则)
    • 为应用添加自定义路由转换器
from flask import Flask
from werkzeug.routing import BaseConverter
app = Flask(__name__)
class CustomConverter(BaseConverter):
    regex = '\w{3}' # 3个字符
app.url_map.converters['abc']=CustomConverter
@app.route('/user/')
def index(mobile):
    print(mobile)
    return 'index'
if __name__=='__main__':
    print(app.url_map.converters) #打印所有路由转换器
    print('------------------')
    app.run()

使用postment分别发送get请求:http://127.0.0.1:5000/user/zhu
运行结果:

lt': werkzeug.routing.UnicodeConverter'>, 'string': werkzeug.routing.UnicodeConverter'>, 'any': werkzeug.routing.AnyConverter'>, 'path': werkzeug.routing.PathConverter'>, 'int': werkzeug.routing.IntegerConverter'>, 'float': werkzeug.routing.FloatConverter'>, 'uuid': werkzeug.routing.UUIDConverter'>, 'abc': __main__.CustomConverter'>}
------------------
zhu
127.0.0.1 - - [17/Mar/2020 20:24:04] "GET /user/zhu HTTP/1.1" 200 -
请求
  • flask中的请求数据通过request对象来获取
  • 常用的请求属性:
属性 说明 类型
url 记录请求的URL地址 str
method 记录请求使用的HTTP方法 str
headers 记录请求中的报文头 EnvironHeaders 类字典对象
args 记录请求中的查询参数 MultiDict
form 记录请求中的表单数据 MultiDict
data 记录请求的数据,并转换为字符串 bytes
json 记录请求体中的json数据 Dict
files 记录请求上传的文件 MultiDict[str: FileStorage]
from flask import Flask, request
# from werkzeug.datastructures import FileStorage

app = Flask(__name__)


@app.route('/', methods=['get', 'post'])
def index():
    # 获取请求的基础数据
    # print(request.url)  # 请求的URL
    # print(request.method)  # 本次请求的请求方式
    # print(request.headers)  # 获取请求头信息  类字典对象

    # print(request.headers['Host'])
    # print(request.headers.get('Host'))  # 建议使用get方法, 键不存在不报错

    # 请求传递数据 1> URL路径 -> 路由变量  2> 查询字符串 get  3> 请求体  post  4> 请求头 -> request.headers

    # 获取查询字符串 -> request.args  xx?name=zs&age=20  类字典对象
    # print(request.args.get('name'))
    # print(request.args.get('age'))

    # 请求体:   键值对(表单)   文本(json/xml)  文件(图片/音频)

    # 获取post键值对 -> request.form  类字典对象
    # print(request.form.get('username'))

    # 获取post文本数据 -> request.data / request.json
    # print(request.data)  # 返回bytes类型
    # print(request.json.get('age'))  # request.json直接将json字符串转为字典

    # 获取post文件 -> request.files  类字典对象
    file = request.files.get("avatar")  # type: FileStorage
    # print(type(file))  # 返回 FileStorage文件对象
    # 将文件保存到本地
    file.save('4323.jpg')

    # 获取文件的二进制数据
    # img_bytes = file.read()
    # print(img_bytes)

    return "index"


if __name__ == '__main__':
    app.run(debug=True)

使用postman发送请求:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ovrKPdNn-1586763119996)(http://my-picture-1258042328.cos.ap-shanghai.myqcloud.com/flask%E5%9F%BA%E7%A1%80/20200317090928173.png)]
运行结果:
项目中会新出现一个4323.jpg文件

127.0.0.1 - - [17/Mar/2020 21:05:48] "GET / HTTP/1.1" 200 -
响应
1)访问静态资源
  • 可以将静态资源放入项目的static文件夹中,通过内置的静态资源访问路由
    • 如 static目录放入文件 123.jpg, 则访问URL为 http://127.0.0.1:5000/static/123.jpg
  • 可以通过修改flask对象的初始化参数来修改静态资源的存储和访问路径
    • static_folder 修改静态文件的存储目录
    • static_url_path 修改静态文件的访问路径
from flask import Flask

app = Flask(__name__,  # 导入名称, flask会根据该参数查询静态文件的存储路径
            # 官方建议直接使用__name__, 表示从当前目录中查询静态文件存储路径
            static_folder="static1",  # 设置静态文件的存储目录
            static_url_path='/res/img',  # 设置静态文件的URL访问路径 如 127.0.0.1:5000/res/img/123.jpg
            )


if __name__ == '__main__':
    app.run(debug=True)
2)自定义响应对象
  • 视图函数返回的str/bytes类型的数据会被自动包装为Response响应对象,也可以通过创建Response响应对象来自定义响应头等信息
from flask import Flask, make_response, Response
app= Flask(__name__)
@app.route('/demo')
def demo():
    response = make_response('hello')
    response.header['A']=10
    return response
if __name__ == '__main__':
    app.run()

通过postman查看返回的自定义响应头:
flask框架_第10张图片

3)返回json
  • 如果接口现需要返回json数据,在flask中可以直接使用jsonify()函数生成一个json的响应
  • 不推荐时使用json.dumps()直接返回,因为返回的数据要符合 HTTP 协议规范,如果是 JSON 需要指定 content-type:application/json
from flask import Flask, make_response, Response,jsonify
# import json
app = Flask(__name__)
@app.route('demo')
def demo():
    dict_={
   'name':'zhu','age':24}
    return jsonify(dict_)
    # return json.dumps(dict_)
if __name__=='__main__':
    app.run()

通过postman查看返回的自定义响应:
flask框架_第11张图片

4)重定向
  • flask中通过redirect()函数实现重定向功能
  • 配合url反向解析函数url_for()可以减少url重构的开发量
from flask import Flask,redirect,url_for
app=Flask(__name__)
@app.route('/demo1')
def demo1():
    url_=url_for('demo2',userid=1)
    return redirect(url_)
@app.route('/demo2/')
def demo2(userid):
    print(userid)
    return 'demo2'
if __name__ == '__main__':
    app.run()

运行结果:

127.0.0.1 - - [17/Mar/2020 22:40:22] "GET /demo1 HTTP/1.1" 302 -
127.0.0.1 - - [17/Mar/2020 22:40:22] "GET /demo2/1 HTTP/1.1" 200 -
1


5)响应状态码
from flask import Flask, redirect, url_for

app = Flask(__name__)


@app.route('/demo5')
def demo5():
    # 可以通过第二个返回值 来设置自定义的响应状态码   实现自定义的交互规则 700 密码错误 701 用户不存在

    # 返回值:  响应体, 响应状态码, 响应头
    return 'demo5', 700, {
   'B': 40}


if __name__ == '__main__':
    app.run(debug=True)

运行结果:

127.0.0.1 - - [17/Mar/2020 22:44:25] "GET /demo HTTP/1.1" 700 -
状态保持
1)cookie
  • 特点
    • 将数据保存在客户端,可以减轻服务器的压力
    • 访问网站时,浏览器将自动发送cookie数据给服务器
  • 一般用于保存一些不太重要的数据
  • 设置cookie:response.set_cookie(键,值,max_age=最大生存时间)
  • 获取cookie:ressponse.cookie.get(键)
  • 删除cookie:response.delete_cookie(键),删除cookie的本质是将max_age设置为0
from flask import Flask ,make_response, Response, request
app =Flask(__name__)
@app.route('/demo1')
def demo1():
    response= make_response()
    response.set_cookie('name','zhu',max_age=600)
    return response
@app.route('/demo2')
def demo2():
    print(request.cookies.get('name'))
    return 'demo2'
if __name__=="__main__":
    app.run()

运行结果:

127.0.0.1 - - [17/Mar/2020 22:59:31] "GET /demo1 HTTP/1.1" 200 -
127.0.0.1 - - [17/Mar/2020 22:59:35] "GET /demo2 HTTP/1.1" 200 -
zhu
2)session
  • 特点:将数据保存在服务端
  • 一般用来保存一些重要或敏感的数据
  • 设置应用密钥,用于session签名:app.secret_key =‘test’
  • 设置session过期时间,默认31天:app.permanent_session_lifetime = timedelta(days=天数)
  • 设置session:session[键]=值
  • 设置session是否支持过期时间:session.permanent = True
  • 删除session:session.pop(键)
  • 获取session: session.get(键)
  • flask的默认session机制 没有将session数据保存到服务器的数据库中, 而是将session数据编码后保存到了cookie中 (签名cookie机制)
  • 可以使用 flask-session组件 来实现传统的session存储
from flask import Flask session
from datetime import timedelta
app=Flask(__name__)
app.secret_key ='test'
app.permanent_session_lifetime = timedelta(days=7)
@app.route('/demo1')
def demo1():
    session['password']= '123'
    session.permanent=True
    return 'demo1'
@app.route('/demo2')
def demo2():
    print(session.get('password'))
    return 'demo2'
if __name__=='__main__':
    app.run()

运行结果:

127.0.0.1 - - [17/Mar/2020 23:16:44] "GET /demo1 HTTP/1.1" 200 -
123
127.0.0.1 - - [17/Mar/2020 23:17:11] "GET /demo2 HTTP/1.1" 200 -
异常处理
  • flask对http错误进行封装,可以捕获http错误,也可以主动抛出http错误
from flask import Flask ,abort
app = Flask(__name__)
@app.errorhandler(404)
def error_404(error):
    return "

您访问的页面去浪迹天涯了

%s"
% error @app.errorhandler(ZeroDivisionError) def error_zero(error): return '除数不能为0' @app.route('/') #访问其他路由时会捕获404异常,跳到error_404函数 def index(): a=1/0 #产生除数为0的异常,会主动跳到error_zero函数 #abort(500) abort()函数可以主动抛出异常 return 'index' if __name__=='__main__': app.run()

3.高级处理

请求钩子
  • 请求钩子可以对请求的各阶段进行监听, 方便开发者 针对请求完成一些统一的处理, 以便减少重复代码, 作用类比Django中的中间件
  • 一般使用以下四种钩子
    • before_request
      • 每次执行视图函数之前调用
      • 对请求进行一些准备处理
      • 如果在某修饰对的函数中返回了一个响应,视图函数将不再被调用
    • after_request
      • 如果没有抛出错误,每次执行视图函数之后调用
      • 在此函数中可以对响应值在返回之前做最后的处理
      • 接收一个参数:包装好的响应对象
      • 需要将修改后的响应对象返回
    • before_first_request
      • web应用被第一次请求前调用
      • 可以进行web应用初始化处理
    • teardown_request
      • 每次执行视图函数之后调用
      • 无论是否出现异常都会执行,一般用于请求收尾
      • 接收一个参数:错误新信息,如果有相关错误抛出
from flask import Flask ,Response
app= Flask(__name__)
@app.before_request
def br():
    print('before_request')
@app.after_request
def ar(response:Response):
    print('after_request')
    return response
@app.before_first_request
def bfr():
    print('before_first_request')
@app.teardown_request
def tr(error):
    print('reardown_request:%s'%error)
@app.route('/')
def index():
    print('执行视图函数')
    # a=1/0 执行此命令则不会调用before_request钩子
    return 'index'
if __name__ =='__main__':
    app.run()

运行结果:

before_first_request
before_request
执行视图函数
after_request
reardown_request:None
127.0.0.1 - - [18/Mar/2020 10:50:48] "GET / HTTP/1.1" 200 -
蓝图
1)基本使用
  • 蓝图的作用:实现flask项目的模块化
  • 项目模块化主要是将业务以功能模块进行划分,每个功能模块对应一个包,用于存放和其有关的视图/工具/模型文件等,如home,user
  • 对于大型项目,一般每个功能模块对应创建一个蓝图,由多个蓝图代替应用来分别管理各模块的视图
--------- project # 工程目录
  |------ main.py # 启动文件
  |------ user  # 用户模块
  |  |--- __init__.py  # 包的初始化文件, 此处创建蓝图对象
  |  |--- views.py  # 视图文件
  |  |--- ...
  |
  |------ home # 首页模块
  |  |--- __init__.py
  |  |--- views.py  
  |  |--- ...
  |...
代码示例
  • home/init.py 在home包中的初始化文件__init__.py中创建蓝图
from flask import Blueprint
home_blu = Blueprint('home_b',__name__) #创建蓝图
# home_blu:蓝图对象,home_b:蓝图名
from . import views # 导入视图文件
  • home/views.py 在views.py文件中存放视图
from home import home_blu
@home_blu.route('/') #路由不再通过app.route()创建,而是通过蓝图对象.route()来创建
def index():
    return 'index'
  • main.py 在项目的main.py文件中注册蓝图
from flask import Flask
from home import home_blu #导入蓝图
app = Flask(__name__) 
app.register_blueprint(bome_blu) #注册蓝图
if __name__=='__main__':
    print(app.url_map)
    app.run()

运行结果:

Map([<Rule '/' (GET, OPTIONS, HEAD) -> home_b.index>,
 <Rule '/static/' (GET, OPTIONS, HEAD) -> static>])
 127.0.0.1 - - [18/Mar/2020 12:01:22] "GET / HTTP/1.1" 200 -
2)使用细节
  • 蓝图的三个使用细节
    • 创建蓝图时,可以通过url_prefix参数给蓝图定义的录用添加统一的url资源段前缀
    • 蓝图定义的路由,其函数标记为蓝图名.函数名
    • 蓝图也可以设置请求钩子
      • 只有访问该蓝图定义的路由时才会触发
      • 实现局部监听
代码示例
  • home/init.py
from flask import Blueprint
home_blu = Blueprint('home_b',__name__,url_prefix='/home')
# url_prefix参数用来给url添加统一资源前缀
@home_blu.before_request #使用蓝图对象创建钩子
def home_prepare():
    print('home_before_request')
from . import views
  • home/views.py
from flask import url_for
from home import home_blu
@home_blu.route('/demo1') #路由/home/demo1
def demo1():
    return 'demo1'
@home_blu.route('/demo2') #路由/home/demo2
def demo2()
    url1=url_for('home_b.demo1')
    print(url1)
    print('demo2')
    return 'demo2'

运行结果:

Map([<Rule '/home/demo1' (OPTIONS, HEAD, GET) -> home_b.demo1>,
 <Rule '/home/demo2' (OPTIONS, HEAD, GET) -> home_b.demo2>,
 <Rule '/static/' (OPTIONS, HEAD, GET) -> static>])
home_before_request
demo1
127.0.0.1 - - [18/Mar/2020 12:15:56] "GET /home/demo1 HTTP/1.1" 200 -
home_before_request
/home/demo1
demo2
127.0.0.1 - - [

你可能感兴趣的:(python,软件框架)