补充:一个编程思路
需求:做一些邮件短信微信的消息通知,比如账单告警之类的;比如数据库操作,数据库种类繁多;缓存的选择比如redis/memcache,诸如此类需要进行选择配置,如果我们单纯的用函数去实现就要进行判断,选择越多判断就要越多,显然这种写法是不行的,那么由此我们就想到了django的中间件的配置,只需要在配置文件中写上路径就可以了,还有restframework中我们只要在配置文件中写上一些的组件的路径或者名称就可以使用了,我们就可以用这种思路来解决开始的问题
总的流程:我们可以把不同逻辑的处理写成类放在一个包里,把这些类的路径放在配置文件中,在全局文件中引入这个包就会执行这个包的_ _init_ _方法,在init方法中去循环配置文件保存类的值,再进行rsplit根据句点符,就得出了路径个类名,在利用importlib的import_module方法和getattr就得到了类
from s7day140 import settings import importlib """ 配置文件中: MSG_LIST = [ "utils.message.email.Email", "utils.message.msg.Msg", "utils.message.wechat.WeChat", ] """ def send_msgs(msg): for path in settings.MSG_LIST: # m就是路径,c就是类名 m,c = path.rsplit('.',maxsplit=1) # md就是路径对应的py文件(模块) md = importlib.import_module(m) # getattr就拿到了模块中类,然后就可以实例对象了 obj = getattr(md,c)() obj.send(msg)
补充:
1、request.query_string 输出的是字节类型,如果有报错的话就用request.args.get(key)
2、request.url就是代表折请求的所有路径,包括域名和URL数据
类似这样的:http://127.0.0.1:8000/index/?data=sssss
3、request.path就是只是路由匹配的路径部分,没有URL数据
类似这样的:/index
一、闪现(message)
1、流程:利用flask中的flash,向某个地方设置一个值,可以指定一个分类参数,用的时候就可以从保存的地方取出所有值,可以指定分类参数
2、应用:通常用做对临时数据的操作
3、原理:message是一个基于Session实现的用于保存数据的集合,保存到用户对应的session信息中,其特点是:使用一次就删除利用session.pop方法
一定要注意要加secret_key 参数
from flask import Flask,flash,get_flashed_messages,request,redirect from werkzeug.datastructures import ImmutableMultiDict app = Flask(__name__) app.secret_key = 'asdfasdf' @app.route('/index') def index(): val = request.args.get('v') if val == 'oldboy': return 'Hello World!' # 向某个地方设置一个值,category参数是分类的意思 flash('超时错误',category="x1") return "ssdsdsdfsd" # return redirect('/error') @app.route('/error') def error(): """ 展示错误信息 :return: """ # 从某个地方获取设置过的所有值,并指定分类,并清除。 data = get_flashed_messages(category_filter=['x1']) if data: msg = data[0] else: msg = "..." return "错误信息:%s" %(msg,) if __name__ == '__main__': app.run()
二、请求扩展
flask中也为我们提供了一些针对请求之前和响应之后执行的装饰器,以及定制错误信息,自定义模版函数和过滤器(flask中不这么叫)的方法
首先实例化对象,做好准备工作:
from flask import Flask,render_template,request,redirect,session,url_for app = Flask(__name__) app.debug = True app.secret_key = 'siuljskdjfs' ......
@app.route('/index',methods=['GET'])
def index():
print('index函数')
return "Index"
if __name__ == '__main__': app.run()
1、所有请求进入到视图会先执行的方法
@app.before_request def process_request1(*args,**kwargs): print('process_request1 进来了')
2、所有响应都会经过的方法,必须写response参数,还要返回response
@app.after_request def process_response1(response): print('process_response1 走了') return response
注意注意::
(1)执行顺序:before_request按照页面加载的顺序依次执行,after_request按照页面加载的倒叙依次执行
(2)返回值:
@app.before_request装饰的方法一般返回None,若有返回值就不会执行视图了,而是直接从最后一个after_request开始向上执行
after_request要记得返回response
3、只有第一次请求来才会先执行的方法:
可用做一些初始化操作,比如连接数据库
@app.before_first_request def first(*args,**kwargs): pass
4、定制错误信息
# 404是状态码,当状态码为404时就会调用这个方法 # 可以用来定制一些错误显示页面和信息 @app.errorhandler(404) # 必须传一个参数 def error_404(arg): print(arg) # 这个参数的打印结果就是下面的内容,也就是错误的提示信息 # 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your # spelling and try again. return "404错误了"
5、自定制模版中的函数
注意要加括号
@app.template_global() def sb(a1, a2): return a1 + a2
模版中使用:
{{sb(1,2)}}
6、自定制模版的过滤器
注意也要加括号
@app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3
模版中使用
# 1代表第一个参数,2和3是第二和第三个参数 {{ 1|db(2,3)}}
三、中间件
首先要知道我们利用请求扩展里提供的装饰器也能够做一些中间件的事,我们这里说的是根据flask的源码流程进行自定义方法来实现中间件的操作
具体流程:
app.run会执行werkzeug(第三方WSGI模块)中的run_simple方法,继而执行inner方法,继续执行make_server方法,make_sever方法就会返回一个BaseWSGIServer对象,主要是起socket,当有请求过来时就会触发flask的call方法,继而执行wsgi_app方法
利用app.run中的wsgi_app方法可以自定义类,定义的_ _call_ _方法里就可以做一些中间件的事
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello World!' class Md(object): def __init__(self,old_wsgi_app): self.old_wsgi_app = old_wsgi_app def __call__(self, environ, start_response): print('开始之前') ret = self.old_wsgi_app(environ, start_response) print('结束之后') return ret if __name__ == '__main__': app.wsgi_app = Md(app.wsgi_app) app.run()
四、蓝图blueprint
作用就是构造自己的程序目录
因为一个项目我们不可能只写一个py文件,当我们把不同的逻辑处理写成几个py文件后,怎么运行,怎么把路由关系建立起来就是个问题,当然我们可以自己写只要导入其它所有的py文件就可以了但这样的话一个是繁琐二是局限性特别大
蓝图就为我们提供了构造程序目录的方法,下面以一个简单应用程序为例:
首先我们就要想怎么就能一启动项目所有的py文件也会跟着执行,这就用到了模块包的__init__方法,所以我们就想到在init中把所有的py文件都导入,在项目的入口文件中只需要导入这个模块包就可以了,但是蓝图的思路就是把每个业务的py文件中实例蓝图对象,这个蓝图对象只对当前py文件有效,我们就可以写路由的对应关系了,在整个业务py文件的包的init文件中实例Flask对象app,把每一个蓝图对象注册到这个app对象中,这样所有的路由映射关系就都在app对象里了,在项目的入口文件中只要导入init文件中的app对象,整个流程就可以启动了
》》目录结构:
static是静态文件目录,默认就叫static,这里的statics是在实例化Flask对象时设置的
templates也是默认的模版文件目录
views是我们创建的不同业务逻辑的py文件
run.py就是项目的入口
》》__init__文件中:
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask # 参数 # template_folder指定模版文件目录 # static_folder指定静态文件目录 # static_url_path指的是静态文件的请求url,意思就是必须往这个url发请求 # flask才会去指定的静态文件目录中查找 app = Flask(__name__,template_folder='templates',static_folder='statics',static_url_path='/static') from .views.account import account from .views.blog import blog from .views.user import user # 将所有的蓝图对象都注册到app对象中 app.register_blueprint(account) app.register_blueprint(blog) app.register_blueprint(user)
》》业务逻辑的py文件,以account.py为例:
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Blueprint from flask import render_template from flask import request # 实例化蓝图对象 # 也可以指定当前文件的模版文件目录,这个目录别的py文件是无法使用的 account = Blueprint('account', __name__,template_folder='mytemplates') # 建立路由映射关系,只对当前文件有效 @account.route('/login', methods=['GET', "POST"]) def login(): return render_template('login.html')
》》项目的入口run.py
from pro_flaskk import app # 引入init文件中的app对象 if __name__ == '__main__': app.run()