Flask快速入门

1.框架

Django(MVT)&Flask(轻量级,代码多,类比Java的SpringMVC) 主要实现了路由分发模板渲染功能

使用 pipenv 搭建虚拟环境,当然也可以使用 virtualenv,所有的包都注意版本兼容(最新)

python 复制代码
from flask import Flask

# TODO:__name__ : 当前的文件所在目录就是flask项目目录,会在项目目录下寻找静态文件夹和模板文件。
# TODO : app: 贯穿整个项目,绑定路由,运行项目。
# 1: 创建视图应用 ctrl + p: 提示参数  command + p(苹果)
app = Flask(__name__)

# 2: 编写视图函数,绑定路由
#默认127.0.0.1:5000/
@app.route('/') # 参数1:路由地址信息
def hello_func():# 无需写request,导包就可以了。
    # 在flask中返回的内容会被包装成响应对象
    return "hello word"

# 3:运行flask:默认是5000端口
if __name__ == '__main__':
    # run的参数 debug的优点: 1: 修改自动重启 2:定位bug
    app.run(host='0.0.0.0', port=8000, debug=True)
    # app.run()
启动

方式一run

方式二配置

export FLASK_APP = 当前路径下的文件名。

export FLSK_ENV = development

flask run -h ip地址 -p 端口号

2.路由

结果:返回一个Map类,类中是一个列表,列表分为三部分:路由,请求方式,视图。

注意:@app.route('/', methods=['get', 'POST'])

复制代码
1: 如果一个视图没有写请求方式,则flask自动给get,head,options请求。
2: flask提供访问静态资源的路由信息:/static/静态文件名
3: options请求一般用于跨域访问,试探请求。
4: head请求一般用于查看服务器是否存在某种资源。
路由转化器
复制代码
1:格式:<路由转换器的名称:变量名称>
2:转换器父类的所在地:from werkzeug.routing import BaseConverter
3: 在routing.py中存在一个放置路由转换器的字典。键是转换器的名称,值是转换器类名。

自定义转化器

复制代码
1:自定义转换器,继承于BaseConverter
2: 重写regex属性,正则
3: 将自定义路由转换器添加到默认的转换器字典中
4: 使用自定义路由转换器完成转换。
3.请求

不是参数,分装到request( 线程隔离)

python 复制代码
from flask import Flask,request

app = Flask(__name__)

@app.route('/index')
def index():
    print("request.url的类型是 ", type(request.url)) #<class 'str'>
    print("得到的request:", request.url) # 得到的request: http://127.0.0.1:8000/
    return "get_url"

@app.route('/')
def get_remote():
    print("获取访问的用户:", request.remote_user) # 获取访问的用户: None
    print(type(request.remote_user))  # <class 'NoneType'>
    print("获取访问的ip地址:", request.remote_addr) # 获取访问的地址: 127.0.0.1
    print(type(request.remote_addr))  #<class 'str'>
    return "get_remote"

@app.route('/headers')
def get_headers():
    print("获取到的请求头是:", request.headers)
    print("获取到的请求头类型是", type(request.headers)) # 字典对象:获取到的请求头类型是 <class 'werkzeug.datastructures.EnvironHeaders'>
    print("获取请求头中的单个信息", request.headers.get('host')) # 找不到返回空
    print("获取请求头中的单个信息", request.headers['host']) # 找不到报错
    return "get_headers"

@app.route('/methods')
def get_methods_cookies():
    # 注意获取到的是大写的,如果以后要判断方式一定要考虑大写。
    print("获取到的method是: ", request.method) # 获取到的method是:  GET
    print(type(request.method)) # <class 'str'>
    print("获取到的cookies是:", request.cookies) # 获取到的cookies是: ImmutableMultiDict([])
    print(type(request.cookies)) # <class 'werkzeug.datastructures.ImmutableMultiDict'>
    return "get_methods_cookies"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=True)

方法和属性:获取请求路径,访问的用户和地址,请求头,请求方式和cookies

4.响应
python 复制代码
from flask import Flask, Response, make_response, render_template, jsonify, redirect, url_for

app = Flask(__name__,  # 导入名称, flask会根据该参数查询静态文件的存储路径
            # 官方建议直接使用__name__, 表示从当前目录中查询静态文件存储路径
            static_folder="static1",  # 设置静态文件的存储目录
            static_url_path='/res/img',  # 设置静态文件的URL访问路径 如 127.0.0.1:5000/res/img/123.jpg
            )
#如果取消转换ASCII编码:增加这个配置。
app.config['JSON_AS_ASCII'] = False


@app.route('/demo1')
def demo_01():
    # 返回多个值,python会封装成元组,然后返回
    return "我是响应体信息", 200, {'name':'www'}

@app.route('/demo2')
def demo_02():
    # 1: 创建响应对象
    response = make_response('我是响应体') # type: Response
    # 2:自定义状态码
    response.status_code = 201
    # 201表示新建资源
    # 3:自定义响应头
    response.headers['name'] = 'www'
    # 4: 设置cookie
    # 5: 返回响应对象
    return response

@app.route('/demo3')
def demo_03():
    return render_template("index.html")

@app.route('/json2')
def demo_func():
    # 1: 准备数据
    my_dict = {
        'name': 'www',
        'age': 23
    }
    # 1: 将字典转换成json字符串
    # 2: 将json字符串包装成响应对象,然后在响应头中设置了响应类型:Content-Type: application/json
    json_str = jsonify(my_dict)
    return json_str

@app.route('/')
def demo_redirect():
    url = 'https://www.baidu.com'
    return redirect(url)

@app.route('/demo')
def demo_redirect2():
    # 路由反转: 根据路由名称获取url地址
    url = url_for('demo_redirect')
    return redirect(url)

if __name__ == '__main__':
    app.run(debug=True)
访问静态资源
复制代码
1:将静态资源放入到 项目的 static 文件夹中。
2:通过内置的静态资源的访问路由, URL路径格式为 /static/<filename> 案例:如 static目录放入文件 123.jpg, 则访问URL为 http://127.0.0.1:5000/static/123.jpg
3:返回模板文件作为响应
设置响应数据
  1. 三个返回值(元组):响应体 (字符串),状态码 (数字),响应头(字典)
  2. 自定义响应对象:使用make_response()函数创建响应对象,请求头无中文,态码只能是数字
返回JSON

jsonnify✔️

重定向

redirect()函数:重定向函数。

url_for()函数:路由反转函数。根据视图名,得到url路径。

5.状态保持

cookie设置响应头的set cookie字段 value必须是str/bytes类型,删除置0

session本质不是全局变量,是一个字典,服务器端,线程id隔离,设置加密密钥,有效期

JWT tocken准备载荷和密钥和过期时间(expire名字固定)

异常处理
复制代码
捕获http错误
@app.errorhandler(404)
还可以捕获系统内置错误
@app.errorhandler(ZeroDivisionError)
6.高级处理
6.1请求钩子

是框架提供的生命周期拦截点,类似中间件

py 复制代码
from flask import Flask, make_response, Response, request

app = Flask(__name__)

#请求钩子
# @app.before_first_request
# def inital():
#     """
#     第一次请求之前调用,并且只会调用一次。
#     作用:项目的初始化操作
#     :return: 不要返回值,如果存在返回值会之间返回给前端,就进入不了视图函数
#     """
#     print("请求之前,只调用一次")

@app.before_request
def process_request():
    """
    每次请求之前调用
    作用:封ip, 统一用户权限认证(cookie session jwt),用户信息的提取
    :return:不需要返回值
    """
    # black_list=[]
    # if request.remote_addr in black_list:
    #     return "IP不允许访问"
    print("请求之前调用,每次请求都会调用")

@app.after_request
def process_response(response):
    """
    # 每一次视图执行之后调用。
    作用:拦截响应对象进行统一设置。
    :param response:视图函数返回的响应。
    :return: 一定要返回响应,不返回前端获取不到响应。
    """
    print("我在请求之后被调用了,每次请求之后都会被调用")
    return response

@app.teardown_request
def process_error(error):
    """
    每次请求结束的时候调用
    作用:判断处理异常,收尾工作
    :param error:异常处理对象
    :return:
    """
    print(error)
    print("我会接收异常信息")

@app.route('/login')
def login():
    print("我是视图函数,我被调用了")
    return ""

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=True)

三个函数是装饰器

flask2.3 版本之后before_first_request被移除

装饰器两种执行方式:

复制代码
方法1:语法器
@app.after_request
def func():
	pass
方法2:装饰器理解成函数
@app.after_request(process_response)

appa和中间件不同时写,无@

复制代码
def view_func():
	pass
app.before_request(view_func)
6.2蓝图

MVT

  • 代码eg. ,小心循环导包,系统同名模块

    1: 在模块的初始化文件,创建蓝图对象。
    2:在视图文件中,利用蓝图对象绑定路由信息。
    3:将蓝图对象注册到app中。
    4:在模块的初始化文件中导入视图文件中的视图。

蓝图其他参数

1:创建蓝图时, 可以通过 url_prefix参数 给蓝图定义的路由添加 统一的URL资源段前缀。

python 复制代码
from flask import Blueprint
"""
1: 蓝图中可以创建属于自己的模板和静态文件
2: 创建蓝图对象的参数: 蓝图名称, 导包路径
"""
# 1: 创建蓝图对象
home_bp = Blueprint("home", import_name=__name__, url_prefix="/home")

from home.views import *

2:蓝图定义的路由, 其函数标记为 蓝图名.函数名。

python 复制代码
from flask import url_for

from home import home_bp
"""
蓝图对象没有注册视图路由的能力
"""
@home_bp.route('/home')
def home_page():
    url = url_for("home.home_page")
    print(url)
    return "home page"

3:蓝图也可以 设置请求钩子,但是只有访问该蓝图定义的路由时才会触发,实现局部监听。

python 复制代码
from flask import Blueprint
"""
蓝图中创建的钩子函数,只对当前蓝图起作用,对其他蓝图不起作用
"""
# 1: 创建蓝图对象
home_bp = Blueprint("home", import_name=__name__, url_prefix="/home")

@home_bp.before_request
def home_pre_prepare():
    print("home_prepare")

from home.views import *
6.3上下文

1:上下文就是一个数据容器

2:上下文分为请求上下文 (request和session)和应用上下文 (current_app 和 g)。

3:导包都是from flask import request, session, current_app, g。

4:本质都不是全局变量,底层通过线程进行了隔离。

5:生命周期:请求开始时创建,返回响应时销毁。

6:作用范围:默认只能视图函数内部使用,函数外部使用会报错。

py 复制代码
#手动开启应用上下文
with app.app_context():
	print(corrent_app)
  • 当模块中够不到app时,想调用app中的配置,使用current_app获取。
  • g能在钩子函数和视图函数进行参数传递。能够在视图函数和自定义函数之间进行参数传递。
    每一次请求之后会清空钩子函数内部的值。
  • 上下文机制不是全局变量,线程隔离
  • 设置使用范围为节省内存
    请求开始时,创建上下文(记录上下文变量)
    请求结束时,销毁上下文(将上下文变量删除,数据占用的空间被释放
6.4综合认证

统一认证

py 复制代码
from flask import Flask, session, g, abort

app = Flask(__name__)
app.secret_key = 'test'

def login_required(view_func):
    def wrapper(*args,**kwargs):
        #1.装饰器代码
        #判断是否登录
        if g.user_name and g.user_id:
            return view_func(*args,**kwargs)
        else:
            abort(401)#权限认证失败
    #2,原函数
    return wrapper
#统一处理
@app.before_request
def prepare():
    # 使用g变量来获取用户名
    g.user_name =session.get('user_name')
    g.user_id = session.get('user_id')

@app.route('/login')
def login():
    session["user_name"]="www"
    session["user_id"] = 23
    return 'login success'

@app.route('/')
def index():
    # 直接拿过来使用
    if g.user_name and g.user_id:
        return "欢迎:{}".format(g.user_name)
    else:
        return '首页'

#登录后点赞
@app.route('/like')
def like():

    print("点赞成功")
    return 'success'

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

需求: 获取用户身份

分析: 除了静态资源,基本所有视图都需要获取用户身份,每个视图单独获取出现大量的代码冗余

解决办法: 设置 请求钩子 ,并通过 g变量 将数据传递给视图函数

访问限制

代码demo5

先登录再...(封装成装饰器先装饰路由,再装饰登录)

装饰器主动装饰视图函数--也能防止装饰器修改被装饰函数名称和文档

6.5应用配置
python 复制代码
# 方案二 创建一个配置基类
app.config.from_object(DevelopmentConfig)
# 方案三: 从环境变量中加载配置信息
app.config.from_envvar("CONFIG", silent=True)
# 方案一:
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = "python39"
app.config['TESTING'] = True
app.config['LJSON_AS_ASCII'] = False

加载配置

1: 使用app.config 配置字典 添加配置信息[少量 配置信息]

2: 使用app.config.from_object 配置类 setting.py✔️

3: 使用**app.config.from_envvar ** 环境变量

工厂方法:

7.flask-restful风格

三步操作:

  1. 创建扩展/组件对象:组件对象=Api(app)

  2. 定义类视图:class 自定义视图类(Resource)

  3. 组件添加类视图: 组件对象.add_resource(视图类,URL资源段)

    返回字典,底层转化为json字符串

7.1视图
类视图添加装饰器

方案一:method_decorators列表的形式。

方案二:method_decorators字典的形式。

  • (同中间件)装饰的顺序是:先装饰列表前面的,再装饰后面的
  • 执行顺序是:先执行后面的,再执行前面的。
单例设计模式

耗时op:权限认证封装成单例

蓝图和类视图
  1. 创建蓝图对象 蓝图对象=Blueprint('蓝图名',_ _name __)
  2. 每个蓝图分别创建组件对象(1.) 组件对象=Api(蓝图对象)
  3. 组件对象添加类视图 (3.) 组件对象.add_resource(视图类,URL资源段)
  4. 应用注册蓝图 应用对象.register_blueprint(蓝图对象)
7.2请求
  • 1.获取参数2.参数校验3.逻辑处理4.返回值处理

  • RequestParser 请求解析(含1.2),步骤:

    • 代码
    1. 创建请求解析器 请求解析器=RequestParser()
    2. 添加参数规则 请求解析器.add_argument(参数名,参数规则...)
    3. 执行解析 参数对象=请求解析器.parse_args()
    4. 获取参数 参数对象.参数名
  • type的三中类型:

    1: python自带的类型

    2:flask_restful自己内置的

    3:自己定义的函数/类。

7.3响应
序列化
  1. 序列化规则=(字段名:序列化类型)
  2. marshsl 函数 按照序列化规则 将模型对象转为字典 序列化后的字典=marshal(模型对象,序列化规则)
    • 方案三:代码demo8
自定义Json
复制代码
api.representation(mediatype="application/json")(output_json)
8.flask-sqlalchemy扩展

SQLAlchemy 是目前python中最强大的 ORM框架

MariaDB数据库(Mysql社区版)

8.1基本使用
  1. 在app对象中添加数据库连接配置信息
  2. 创建数据库对象-绑定应用对象
  3. 自动以模型类
  4. 根据模型类创建所有的表结构
8.2数据操作

自定义模型类(创建表),懒加载

增加数据
复制代码
@app.route('/')
def index():
    """增加数据"""

    # 1.创建模型对象
    user1 = User(name='zs', age=20)
    #  = 'zs'
    # user1.age = 20

    # 2.将模型对象添加到会话中
    db.session.add(user1)
    # 添加多条记录
    # db.session.add_all([user1, user2, user3])

    # 3.提交会话 (会提交事务)
    # sqlalchemy会自动创建隐式事务
    # 事务失败会自动回滚
    db.session.commit()

    return "index"
查询数据
修改数据

方案一:先查询再更新

方案二:配合查询过滤器filter() 和 更新执行器update() 进行数据更新✔️

复制代码
Goods.query.filter( == '方便面').update({'count': Goods.count - 1})
    db.session.commit()
删除数据

方案一: 先查后删除

复制代码
goods = Goods.query.filter( == '方便面').first()
# 删除数据
db.session.delete(goods)
# 提交会话 增删改都要提交会话
db.session.commit()

方案二:delete子查询

复制代码
Goods.query.filter( == '方便面').delete()
# 提交会话
db.session.commit()
8.3高级机制

https://blog.51cto.com/u_15317888/4953364

刷新数据

1:Session 会先将操作产生的数据保存到内存中。

2: 在执行 flush刷新操作后, 数据操作才会同步到数据库中。

3:隐式刷新操作:1:提交会话 2:查询操作(包括更新和删除中的子查询)。

4:手动刷新:session.flush()

eg.收获地址(不注册可购买)

多表连接,flush(不提交事务)✔️&commit❌

Flush本质把ORM转化的sqI提交到数据库执行sql语句

django事务(默认关)&Flask-sqlalchemy(默认开,怎删改查都需commit)

多表查询

关系属性:oop外键

  1. 定义关系属性 关系属性名=db.relationship(关联数据所在的模型类")
  2. 外键字段设置外键参数 外健字段=db.Column(字段类型,db.ForeignKey(主表名,主键名))
  3. 通过关系属性获取关联数据 模型对象,关系属性

join连接查询

复制代码
db.session.query(主表模型字段1,主表模型字段2,从表模型字段1,xx..).join(从表模型类, 主表模型类.主键 == 从表模型类,外键)
Session机制
  • Session中可以包含多个事务,提交事务失败后,会自动执行SQL的回滚操作
  • 同一个谓求中,想要在前一个事多失败的情况下创建新的事务,必须先手动回滚事务Session.rollback
相关推荐
天南星7 分钟前
java-WebSocket在Java生态中的发展历程
java·后端·websocket
工藤学编程32 分钟前
分库分表之实战-sharding-JDBC绑定表配置实战
数据库·分布式·后端·sql·mysql
fmvrj342021 小时前
云原生:数字化转型的核心引擎
后端
RAY_01041 小时前
Python—数据容器
开发语言·python
June bug1 小时前
【python基础】python和pycharm的下载与安装
开发语言·python·pycharm
码出极致1 小时前
Redisson分布式缓存与数据一致性保障
后端
用户790349033711 小时前
springboot集成redisson实现redis分布式锁
后端
陈随易1 小时前
程序员的新玩具,MoonBit(月兔)编程语言科普
前端·后端·程序员
码出极致1 小时前
Redisson秒杀系统中的分布式锁应用
后端
xiaok1 小时前
@Param注解的作用
java·后端