2691 字
13 分钟
Flask学习记录
2024-04-27

Flask学习记录#

flask run启动#

新版flask在linux中的运行方式#

先在环境变量中指定要运行哪个文件,比如要运行的是helloworld_server.py文件

export FLASK_APP=helloworld_server

对于win环境,则使用

$env:FLASK_APP = "helloworld_server"

然后如果要运行在开发模式则需要输入:(前面是linux环境命令,后面是win环境命令)

export FLASK_ENV=development
$env:FLASK_ENV="development"

然后执行(后面的可以指定ip和端口)

flask run
flask run -h 0.0.0.0 -p 50001

export FLASK_ENV=production运行在生产模式,未指明则默认为此方式 export FLASK_ENV=development运行在开发模式

flask routes查询路由#

注意,需要先在环境变量中指定要运行的是哪个文件,才能使用flask routes查询这个文件中的路由

定义路由的请求方式#

有三种:

GET

OPTIONS(自带)

HEAD(自带)

methods参数指定请求方式#

method指定的是一个列表,里面可以有多种支持的请求方式

@app.route("/itcast1", methods=["POST"])
def view_func_1():
return "hello world 1"
@app.route("/itcast1", methods=["GET", "POST"])
def view_func_2():
return "hello world 2"

蓝图的使用#

单一文件定义蓝图#

# 8创建蓝图对象
user_bp = Blueprint('user', __name__)
# 9编写蓝图视图
@user_bp.route('/profile')
def get_profile():
return 'get_profile'
# 10注册蓝图
# app.register_blueprint(user_bp)
# 11指定蓝图的url前缀
app.register_blueprint(user_bp, url_prefix='/user')

目录定义蓝图#

1、先有目录,然后有__init__.py文件和views.py文件

views.py里是蓝图对应的视图代码

__init__.py文件中编写代码:

# 0导包
from flask import Blueprint
# 1创建蓝图对象
goods_bp = Blueprint('goods', __name__, url_prefix='/goods')
# 2导入views.py,不导入的话不会执行views.py中的代码,就不能访问视图函数
from . import views

views.py文件编写代码:

# 0导入蓝图对象
from . import goods_bp
# 1编写蓝图视图
@goods_bp.route('/getgoods')
def get_goods():
return 'goods'

2、在创建flask应用的文件里把蓝图注册到app

# 12 注册goods包中的蓝图,注意这里导包是从goods路径导入__init__.py文件中的gods_bp,如果写成from goods.__init__会访问不了蓝图
from goods import goods_bp
app.register_blueprint(goods_bp)

蓝图必须显示指明静态文件目录#

不像默认的static文件夹一样,蓝图里的静态文件不会被默认寻找,只有显示指定静态文件目录才会去找

admin = Blueprint("admin",__name__,static_folder'static_admin')
app.register_blueprint(admin,url_prefix='/admin')

也可通过 static_url_path 改变访问路径

admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')

从url路径获取参数#

直接获取

# 13从url路径中获取参数
@user_bp.route('/profile/<user_id>')
def get_profile_by_id(user_id):
return 'get_profile_by_id:{}'.format(user_id)

转换器配合正则表达式使用#

# 14使用转换器配合正则表达式
@user_bp.route('/profile/<int:user_id>')
def get_profile_by_id(user_id):
return 'get_profile_by_id:{}'.format(user_id)

转换器内置的类型:

  • default
  • string
  • any
  • path
  • int
  • float
  • uuid

自定义转换器类型#

# 15自定义转换器
# 16导包并编写类
from werkzeug.routing import BaseConverter
class MobileConverter(BaseConverter):
"""自定义转换器"""
regex = r'1[3-9]\d{9}'
# 17将自定义的转换器告知flask应用
app.url_map.converters['mobile'] = MobileConverter
# 18使用自定义转换器
@app.route('/sms_codes/<mobile:mob_num>')
def send_sms_code(mob_num):
return 'send_sms_code:{}'.format(mob_num)

request对象的使用#

request对象中封装了以下内容:

data记录请求的数据,并转为字符串(请求体)*
form记录请求中的表单数据MultiDict
args请求中的参数MultiDict
cookies请求中的cookie信息Dict
headers请求头EnvironHeaders
method请求方法GET/POST
url请求的URL地址string
files请求上传的文件*

从请求中获取参数#

# 19request对象的使用,要先导入request包
# /articles?channel_id=123
@app.route('/articles')
def get_articles():
channel_id = request.args.get('channel_id')
return 'get_articles:{}'.format(channel_id)

从请求中获取文件#

# 20提取request中的文件
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['pic']
# 手动打开文件
with open('./demo.jpg', 'wb') as new_file:
new_file.write(file.read())
# flask提供的保存文件方法
file.save('./demo.jpg')
return 'ok'

处理响应render_template#

使用模板文件夹中的文件去处理响应

# 0导包
from flask import Flask, request, Blueprint
app = Flask(__name__)
# 1导入模板响应需要的包
from flask import render_template
# 2使用render_template函数去渲染模板,传参直接传递参数
# 在模板中通过{{my_str}}和{{my_int}}去获取参数
@app.route('/')
def index():
# 普通变量直接传
#my_str = 'hello world'
#my_int = 100
#return render_template('index.html', my_str=my_str, my_int=my_int)
# 字典要保证字典中的key和模板中的变量名一致
data = dict(
my_str='hello world',
my_int=1233
)
return render_template('index.html', **data)
# 这行传字典,等价于下面这行,所以要保证字典中的key和模板中index.html的变量名一致
# return render_template('index.html', my_str='hello world', my_int=1233)

重定向#

# 3重定向,先导包
from flask import redirect
@app.route('/demo')
def demo():
return redirect('http://www.itheima.com')

返回json#

# 4返回json数据
# 先导包
from flask import jsonify
@app.route('/json')
def json():
json_dict = {
"user_id": 1001,
"user_name": "itcast",
"age": 18
}
return jsonify(json_dict)

响应的返回#

# 5响应有两种返回方式
# 元祖返回响应
@app.route('/demo4')
def demo4():
# 注意格式是(response,status,headers),如果不足3个,则从右边开始缺省
# 例如写了status,那必须要有response
return '状态码为 666', 666, {'Itcast': 'python'}
# make_response返回响应
from flask import make_response
@app.route('/demo5')
def demo5():
response = make_response('状态码为 666')
response.headers['Itcast'] = 'python'
response.status_code = 666
return response

设置cookie只能通过make_response#

# 6设置cookie
from flask import make_response
@app.route('/cookie')
def set_cookie():
response = make_response('设置cookie成功')
# 第一个参数是cookie的名称,第二个参数是cookie的值,第三个参数是cookie的过期时间,可以没有第三个参数
response.set_cookie('username', 'itcast', max_age=3600)
return response

读取cookie的值#

# 7读取cookie的值
@app.route('/get_cookie')
def get_cookie():
username = request.cookies.get('username')
return username

删除cookie的值#

# 8删除cookie
@app.route('/delete_cookie')
def delete_cookie():
response = make_response('删除cookie成功')
response.delete_cookie('username')
return response

session对象#

设置session#

# 9设置session,注意在使用session之前,必须先设置secret_key
# 先导包
from flask import session
@app.route('/set_session')
def set_session():
session['username'] = 'itcast'
return '设置session成功'

读取session#

#10读取session
@app.route('/get_session')
def get_session():
username = session.get('username')
return '获取到session数据:{}'.format(username)

异常处理#

http异常主动抛出用abort()#

# 11使用abort函数,直接返回错误响应,要先导包
from flask import abort
@app.route('/article')
def get_article():
channel_id = request.args.get('channel_id')
if channel_id is None:
abort(404)
else:
return '获取文章成功,channel_id:{}'.format(channel_id)

装饰器捕获异常#

# 12捕获异常,用装饰器
@app.errorhandler(500)
def internal_server_error(e):
return '服务器搬家了', 500
# 13也可以捕获特定的异常
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除数不能为0'
@app.route('/zero')
def zero():
a = 1/0
return 'zero 函数'

请求钩子hook#

就是中间件的作用

请求的处理过程:pre_process -> view -> after_prosess

middleware1.pre_process() -> m2.pre_process() -> m3.pre_process()->view0 -> m3.after_process() -> m2.after_process() ->m1.after_process() -> client

中间件处理不区分具体是哪个视图,对所有视图通通生效

有四中处理的方法:

before_first_request:只在第一次接收到请求时处理,在视图前

before_request:每次请求前执行,在视图前

after_request:如果没有抛出异常,在每次请求后执行

teardown_request:在每次请求后执行

上下文#

分为:请求上下文和应用上下文

请求上下文#

有两个,request和session

应用上下文#

current_app:当前应用

使用场景:在另一个文件中要使用到其他文件中创建的app对象,直接import有循环引用的风险

from flask import Blueprint, current_app
bp = Blueprint('passprot', __name__)
@bp.route('/bp')
def viewfunction():
# 这行相当于 app.config.get('Itcast')
current_app.config.get('Itcast')
pass

g对象:省去传递参数的声明,只在一次请求的期间传递,下一次请求存下一次请求的数据

# 18g对象可以存取当前请求的数据,免于传参
# 先导包
from flask import g
# 普通传参方式
def db_query_1(user_id, user_name):
return 'db_query_1:{}, {}'.format(user_id, user_name)
# g对象方式
def db_query_2():
user_id = g.user_id
user_name = g.user_name
return 'db_query_2:{}, {}'.format(user_id, user_name)
@app.route('/g')
def get_user_profile():
# user_id = 123
# user_name = "itcast"
# ret = db_query_1(user_id, user_name)
g.user_id = 456
g.user_name = "itcast"
ret = db_query_2() # 不用考虑传参
return ret

正式开始写项目#

通过endpoint给路由起别名#

# 起别名是给这个HelloWorldResource, '/'这一组起别名
api.add_resource(HelloWorldResource, '/', endpoint='HelloWorld')

flask_result的路由#

# -*- conding:utf-8 -*-
# 0导包
from flask import Flask
from flask_restful import Resource, Api
# 1创建app
app = Flask(__name__)
api = Api(app)
# 2创建类视图
class HelloWorldResource(Resource):
def get(self):
return {'hello': 'world'}
def post(self):
return {'msg': 'post hello world'}
# 3注册路由,参数是类视图对应的类,和访问路径
api.add_resource(HelloWorldResource, '/')

flask_result的蓝图#

# 4给蓝图导包
from flask import Blueprint
# 5创建蓝图对象
user_bp = Blueprint('user', __name__)
# 6使用蓝图,api对象不再和全局的app对象绑定,而是和蓝图绑定,得到蓝图里的api对象
user_api = Api(user_bp)
# 7蓝图的类视图
class UserProfileResource(Resource):
def get(self):
return {'msg': 'get user profile'}
# 8用蓝图里的api对象收集路径信息,api绑定的哪个对象,收集到的路径信息就传给哪个对象
user_api.add_resource(UserProfileResource, '/user/profile')
# 9蓝图对象注册到全局app
app.register_blueprint(user_bp)

给类视图加装饰器#

# 10给不同的请求方法加不同的装饰器,写在后面的装饰器会先被调用
# 首先创建装饰器
def decorator1(func):
def wrapper(*args, **kwargs):
print('call decorator1')
return func(*args, **kwargs)
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print('call decorator2')
return func(*args, **kwargs)
return wrapper
# 11创建装饰器类
class DemoResource(Resource):
method_decorators = {
'get': [decorator1, decorator2],
'post': [decorator1]
}
# 使用了[decorator1, decorator2]两个装饰器
def get(self):
return {'msg': 'get view'}
# 使用了[decorator1]装饰器
def post(self):
return {'msg': 'post view'}
# 未使用装饰器
def put(self):
return {'msg': 'put view'}
# 12把类视图注册到路由
api.add_resource(DemoResource, '/DemoResource')

关于请求处理参数#

# 13使用RequestParser进行校验
# 导包
from flask_restful.reqparse import RequestParser
# 创建视图类
class RequestParserDemo(Resource):
def get(self):
# 创建RequestParser类对象
request_parser = RequestParser()
# 声明参数
request_parser.add_argument('a')
request_parser.add_argument('b')
# 执行校验
request = request_parser.parse_args()
# 可以把request当做字典,也可以当做对象
# a = request['a']
a = request.a
return {'a': a}
# 14把类视图注册到路由
api.add_resource(RequestParserDemo, '/RequestParserDemo')

有四个字段

例如:

request_parser.add_argument('b', type=int, required=True, help='missing b', action='append')

1 required#

请求是否一定要携带参数,默认为false

2 help#

参数检验错误时返回到错误描述信息

3 action#

对于请求参数中出现多个同名参数时的处理方式

action=‘store’保留出现的第一个,默认

action=‘append’以列表追加保存所有同名参数的值

4 type#

描述参数应该匹配的类型

有三种可以匹配的类型

1、Python标准类型

2、Flask-RESTful提供的类型(检验类型方法在flask_restful.inputs模块中)

  • url

  • regex(指定正则表达式)

    • from flask_restful import inputs
      request_parser.add_argument('a', type=inputs.regex(r'^\d{2}&'))
  • natural:自然数0、1、2、3..

  • positive:正整数1、2、3..

  • int_range(low, high):整数范围

    • from flask_restful import inputs
      request_parser.add_argument('a', type=input.int_range(1, 10))
  • boolean

3、自定义

5 location#

描述参数应该在请求数据中出现的位置

也可指明多个位置

request_parser.add_argument('text', location=['headers', 'json'])

关于响应#

# 15处理响应
# 导包
from flask_restful import fields, marshal_with, marshal
# 编写用户类
class User(object):
def __inti__(self, user_id, name, age):
self.user_id = user_id
self.name = name
self.age = age
# 声明需要序列化处理的字段
resource_fields = {
'user_id': fields.Integer,
'name': fields.String
}
# 编写视图类
class Demo1marshal(Resource):
@marshal_with(resource_fields, envelope='data1')
def get(self):
user = User(1, 'itcast', 12)
return user
class Demo2marshal(Resource):
def get(self):
user = User(1, 'itcast', 12)
return marshal(user, resource_fields, envelope='data2')
# 把视图类注册到路由的api
api.add_resource(Demo1marshal, '/demo1marshal')
api.add_resource(Demo2marshal, '/demo2marshal')

自定义返回的json格式#

Flask-RESTful的Api对象提供了一个representation的装饰器,允许定制返回数据的呈现格式

外键可以不设,也可以设置set null,防止删除时报错

Flask学习记录
https://fuwari.cbba.top/posts/flask学习记录/
作者
Chen_Feng
发布于
2024-04-27
许可协议
CC BY-NC-SA 4.0