flask 初识 (类似于django的框架)
我们的flask跟django类似,都是属于一个框架,这个框架更加微型,它里面的功能我们用django都能实现,
它更加轻量级,是基于python开发并且依赖jinja2模板和werkzeug WSGI服务的一个微型框架,对于werkzeug本质是socket服务端,其用于接收http请求并对请求进行预处理,然后触发flask框架,开发人员基于flask框架提供的功能对于请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinjia2模板来实现对模板的预处理,即将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器
flask麻雀虽小,五脏俱全,它的核心简单而易于扩展.flask不会替你做出太多决策,---比如使用何种数据库,而那些flask所选择的---比如使用何种模板引擎---则很容易替换.除此之外的一切都是可以自定义的.
默认情况下,flask不包含数据库抽象层,表单验证,或是其他任何已有多种库可以胜任的功能,然而,flask支持用扩展来给应用添加这些功能,如同是flask本身实现的一样,众多的扩展提供了数据库集成,表单验证,上传处理,各种各样的开发认证技术等功能.

1 s8day123 2 3 内容回顾: 4 1. 装饰器 5 问题:什么是装饰器? 6 问题:手写装饰器 7 问题:装饰器都在哪里用过? 8 9 import functools 10 11 def wapper(func): 12 @functools.wraps(func) 13 def inner(*args,**kwargs): 14 return func(*args,**kwargs) 15 return inner 16 """ 17 1. 执行wapper函数,并将被装饰的函数当做参数。 wapper(index) 18 2. 将第一步的返回值,重新赋值给 新index = wapper(老index) 19 """ 20 @wapper 21 def index(a1): 22 return a1 + 1000 23 24 @wapper 25 def order(a1): 26 return a1 + 1000 27 28 29 print(index.__name__) 30 print(order.__name__) 31 32 2. 谈谈你对面向对象的认识? 33 - 封装: 34 - 将同一类方法分为一类:方法封装到类中 35 - 将方法中共同的参数封装到对象中:把共用值封装到对象中。 36 37 情况: 38 a. BaseReponse 39 def index(a1,a2,a3,a4,a5,a6,a7): 40 pass 41 42 # 用户类实现 43 class Foo(object): 44 def __init__(self,a1,a2,a3,a4,a5,a6,a7): 45 self.a1 = a1 46 self.a2 = a2 47 self.a3 = a3 48 self.a4 = a4 49 self.a5 = a5 50 self.a6 = a6 51 self.a7 = a7 52 53 def index(obj): 54 pass 55 b. 给了一些值,将数据加工: django 自定义分页 56 57 class Foo(object): 58 def __init__(self,a1,a2,a3,a4,a5,a6,a7): 59 self.a1 = a1 60 self.a2 = a2 61 self.a3 = a3 62 self.a4 = a4 63 self.a5 = a5 64 self.a6 = a6 65 self.a7 = a7 66 67 def 金条(self): 68 return self.a1 + self.a2 69 70 def 手表(self): 71 return self.a1 + self.a7 72 73 74 75 今日内容: 76 1. 配置文件 77 2. 路由 * 78 3. 视图函数 79 4. 请求和响应 * 80 5. 模板 81 6. session * 82 83 8. 蓝图 blueprint * 84 10. 中间件 85 7. 闪现 86 87 88 内容详细: 89 1. 配置文件 90 91 2. 路由 92 a. 添加路由的两种方式: 93 from flask import Flask,render_template,redirect 94 app = Flask(__name__) 95 96 """ 97 1. 执行decorator=app.route('/index',methods=['GET','POST']) 98 2. @decorator 99 - decorator(index) 100 """ 101 # 路由方式一(*): 102 @app.route('/index',methods=['GET','POST']) 103 def index(): 104 return "Index" 105 106 # 路由方式二: 107 def order(): 108 return 'Order' 109 110 app.add_url_rule('/order',view_func=order) 111 112 113 if __name__ == '__main__': 114 app.run() 115 b. endpoint(默认函数名) 116 c. 传参数 117 @app.route('/index/<int:nid>',methods=['GET','POST']) 118 def index(nid): 119 print(nid,type(nid)) 120 121 url_for('index',nid=888) 122 123 return "Index" 124 d. 自定义正则参数 125 126 from flask import Flask,render_template,redirect,url_for 127 from werkzeug.routing import BaseConverter 128 app = Flask(__name__) 129 130 131 class RegexConverter(BaseConverter): 132 """ 133 自定义URL匹配正则表达式 134 """ 135 def __init__(self, map, regex): 136 super(RegexConverter, self).__init__(map) 137 self.regex = regex 138 139 def to_python(self, value): 140 """ 141 路由匹配时,匹配成功后传递给视图函数中参数的值 142 :param value: 143 :return: 144 """ 145 return int(value) 146 147 def to_url(self, value): 148 """ 149 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 150 :param value: 151 :return: 152 """ 153 val = super(RegexConverter, self).to_url(value) 154 return val 155 156 app.url_map.converters['xxx'] = RegexConverter 157 158 @app.route('/index/<xxx("\d+"):nid>',methods=['GET','POST']) 159 def index(nid): 160 print(nid,type(nid)) 161 v = url_for('index',nid=999) # /index/999 162 print(v) 163 return "Index" 164 165 if __name__ == '__main__': 166 app.run() 167 168 e. 其他参数 169 - 重定向 170 from flask import Flask,render_template,redirect 171 app = Flask(__name__) 172 173 @app.route('/index',methods=['GET','POST'],redirect_to='/new') 174 def index(): 175 return "老功能" 176 177 @app.route('/new',methods=['GET','POST']) 178 def new(): 179 return '新功能' 180 181 182 if __name__ == '__main__': 183 app.run() 184 185 PS: 前端重定向 186 - meta 187 - js 188 189 重点: 190 - url 191 - methods 192 - endpoint 193 - @app.route('/index/<int:nid1>/<int:nid2>/') 194 - url_for 195 196 197 3. 198 - cbv 199 - fbv 200 201 4. 202 request 203 response = make_response(....) 204 # 响应头 205 # cookie 206 return response 207 208 5. 模板 209 210 6. session 211 212 7. 常见装饰器 213 - before_first_request 214 - before_request 215 - after_request 216 - errorhandler(404) 217 218 8. 闪现 219 220 9. 中间件 221 222 10. 蓝图 223 224 225 11. 补充: 226 - 项目依赖 pip3 install pipreqs 227 - 生成依赖文件:pipreqs ./ 228 - 安装依赖文件:pip3 install -r requirements.txt 229 - 什么是函数?什么是方法? 230 231 from types import MethodType,FunctionType 232 233 class Foo(object): 234 def fetch(self): 235 pass 236 237 print(isinstance(Foo.fetch,MethodType)) 238 print(isinstance(Foo.fetch,FunctionType)) # True 239 240 obj = Foo() 241 print(isinstance(obj.fetch,MethodType)) # True 242 print(isinstance(obj.fetch,FunctionType)) 243 244 245 246 247 248 249 250 251 252
在python环境下安装flask:
pip3 install flask
一,基本使用
from flask import Flask app = Flask(__name__) app.debug=True # 这里的debug设置为True就是出于开发模式,然后我们的flask程序就会自动重启 @app.route('/') def hello(): return "hello world" if __name__ == '__main__': app.run() # 我们的这个文件需要背会,要能够手写出来
from werkzeug.wrappers import Request, Response from werkzeug.serving import run_simple @Request.application def hello(request): return Response("Hello World") if __name__ == '__main__': # 请求一旦到来,执行第三个参数,即上面的函数名 参数() run_simple("localhost", 5000, hello)
二,配置文件
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
{ 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式 '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, 'LOGGER_HANDLER_POLICY': 'always', '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, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
方式一:
app.config['DEBUG']=True
ps:由于Config对象本质上是字典,所以还可以使用app.config.update(...)
方式二:
app.config.from_pyfile('python文件名称')
如:
setting.py
DEBUG=True
app.config.from_pyfile("settings.py")
app.config.from_envvar("环境变量名称")
环境变量的值为python文件名称,内部调用from_pyfile方法
app.config.from_json("json文件名称")
JSON文件名称,必须是json格式,因为内部会执行json.loads
app.config.from_mapping({"DEBUG":True})
字典格式
app.config.from_object("python类或类的路径")
app.config.from_object("pro_flask.settings.TestingConfig")
settings.py
class Config():
DEBUG=False
TESTING=False
DATABASE_URL='sqlite://:memory:'
class ProductionConfig(Config):
DATABASE_URL='mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DEBUG=True
class TestingConfig(Config):
TESTING=True
ps:从sys.path中已经存在路径开始写
PS:settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
三,路由系统
@app.route('/user/<username>') 这个<>括号里面这样写就是匹配字符串 @app.route('/post/<int:post_id>') 这个<>里面加上int:即是匹配数字 @app.route('/post/<float:post_id>') 匹配小数float: @app.route("/post/<path:path>") 匹配路径path: @app.route("/login/",methods=['GET','POST']) 常用路由即以上这些 路由的对应关系如下: DEFAULT_CONVERTERS={ 'defaut':UnicodeConverter, 'string':UnicodeConverter, 'any':AnyConverter, 'path':PathConverter, 'int':IntegerConverter, 'float':FloatConverter, 'uuid':UUIDConverter, }
注册路由原理:

1 def auth(func): 2 def inner(*args, **kwargs): 3 print('before') 4 result = func(*args, **kwargs) 5 print('after') 6 return result 7 8 return inner 9 10 @app.route('/index.html',methods=['GET','POST'],endpoint='index') 11 @auth 12 def index(): 13 return 'Index' 14 15 或 16 17 def index(): 18 return "Index" 19 20 self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"]) 21 or 22 app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"]) 23 app.view_functions['index'] = index 24 25 26 或 27 def auth(func): 28 def inner(*args, **kwargs): 29 print('before') 30 result = func(*args, **kwargs) 31 print('after') 32 return result 33 34 return inner 35 36 class IndexView(views.View): 37 methods = ['GET'] 38 decorators = [auth, ] 39 40 def dispatch_request(self): 41 print('Index') 42 return 'Index!' 43 44 app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint 45 46 47 48 或 49 50 51 class IndexView(views.MethodView): 52 methods = ['GET'] 53 decorators = [auth, ] 54 55 def get(self): 56 return 'Index.GET' 57 58 def post(self): 59 return 'Index.POST' 60 61 62 app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint 63 64 65 66 67 @app.route和app.add_url_rule参数: 68 rule, URL规则 69 view_func, 视图函数名称 70 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 71 endpoint=None, 名称,用于反向生成URL,即: url_for('名称') 72 methods=None, 允许的请求方式,如:["GET","POST"] 73 74 75 strict_slashes=None, 对URL最后的 / 符号是否严格要求, 76 如: 77 @app.route('/index',strict_slashes=False), 78 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 79 @app.route('/index',strict_slashes=True) 80 仅访问 http://www.xx.com/index 81 redirect_to=None, 重定向到指定地址 82 如: 83 @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 84 或 85 def func(adapter, nid): 86 return "/home/888" 87 @app.route('/index/<int:nid>', redirect_to=func) 88 subdomain=None, 子域名访问 89 from flask import Flask, views, url_for 90 91 app = Flask(import_name=__name__) 92 app.config['SERVER_NAME'] = 'wupeiqi.com:5000' 93 94 95 @app.route("/", subdomain="admin") 96 def static_index(): 97 """Flask supports static subdomains 98 This is available at static.your-domain.tld""" 99 return "static.your-domain.tld" 100 101 102 @app.route("/dynamic", subdomain="<username>") 103 def username_index(username): 104 """Dynamic subdomains are also supported 105 Try going to user1.your-domain.tld/dynamic""" 106 return username + ".your-domain.tld" 107 108 109 if __name__ == '__main__': 110 app.run() 111 112 113 a.注册路由原理

1 from flask import Flask, views, url_for 2 from werkzeug.routing import BaseConverter 3 4 app = Flask(import_name=__name__) 5 6 7 class RegexConverter(BaseConverter): 8 """ 9 自定义URL匹配正则表达式 10 """ 11 def __init__(self, map, regex): 12 super(RegexConverter, self).__init__(map) 13 self.regex = regex 14 15 def to_python(self, value): 16 """ 17 路由匹配时,匹配成功后传递给视图函数中参数的值 18 :param value: 19 :return: 20 """ 21 return int(value) 22 23 def to_url(self, value): 24 """ 25 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 26 :param value: 27 :return: 28 """ 29 val = super(RegexConverter, self).to_url(value) 30 return val 31 32 # 添加到flask中 33 app.url_map.converters['regex'] = RegexConverter 34 35 36 @app.route('/index/<regex("\d+"):nid>') 37 def index(nid): 38 print(url_for('index', nid='888')) 39 return 'Index' 40 41 42 if __name__ == '__main__': 43 app.run() 44 45 b. 自定制正则路由匹配
四,模板:
模板的使用跟django别无二致,从模板继承到组件都是一样的逻辑

1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <h1>自定义函数</h1> 9 {{ww()|safe}} 10 11 </body> 12 </html> 13 14 html

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Flask,render_template 4 app = Flask(__name__) 5 6 7 def wupeiqi(): 8 return '<h1>Wupeiqi</h1>' 9 10 @app.route('/login', methods=['GET', 'POST']) 11 def login(): 12 return render_template('login.html', ww=wupeiqi) 13 14 app.run() 15 16 run.py

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 10 {% macro input(name, type='text', value='') %} 11 <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> 12 {% endmacro %} 13 14 {{ input('n1') }} 15 16 {% include 'tp.html' %} 17 18 <h1>asdf{{ v.k1}}</h1> 19 </body> 20 </html> 21 22 其他
我们这里的Markup等同于我们的mark_safe
五,请求和相应

1 from flask import Flask 2 from flask import request 3 from flask import render_template 4 from flask import redirect 5 from flask import make_response 6 7 app = Flask(__name__) 8 9 10 @app.route('/login.html', methods=['GET', "POST"]) 11 def login(): 12 13 # 请求相关信息 14 # request.method 15 # request.args 16 # request.form 17 # request.values 18 # request.cookies 19 # request.headers 20 # request.path 21 # request.full_path 22 # request.script_root 23 # request.url 24 # request.base_url 25 # request.url_root 26 # request.host_url 27 # request.host 28 # request.files 29 # obj = request.files['the_file_name'] 30 # obj.save('/var/www/uploads/' + secure_filename(f.filename)) 31 32 # 响应相关信息 33 # return "字符串" 34 # return render_template('html模板路径',**{}) 35 # return redirect('/index.html') 36 37 # response = make_response(render_template('index.html')) 38 # response是flask.wrappers.Response类型 39 # response.delete_cookie('key') 40 # response.set_cookie('key', 'value') 41 # response.headers['X-Something'] = 'A value' 42 # return response 43 44 45 return "内容" 46 47 if __name__ == '__main__': 48 app.run()
六,Session
除请求对象之外,还有一个session对象.它允许你在不同请求间存储特定用户的信息.它是在Cookie基础上实现的,并且对Cookie进行密钥签名要使用会话,你需要设置一个密钥.
设置:session['username']='peter'
删除:session.pop('username',None)

1 from flask import Flask, session, redirect, url_for, escape, request 2 3 app = Flask(__name__) 4 5 @app.route('/') 6 def index(): 7 if 'username' in session: 8 return 'Logged in as %s' % escape(session['username']) 9 return 'You are not logged in' 10 11 @app.route('/login', methods=['GET', 'POST']) 12 def login(): 13 if request.method == 'POST': 14 session['username'] = request.form['username'] 15 return redirect(url_for('index')) 16 return ''' 17 <form action="" method="post"> 18 <p><input type=text name=username> 19 <p><input type=submit value=Login> 20 </form> 21 ''' 22 23 @app.route('/logout') 24 def logout(): 25 # remove the username from the session if it's there 26 session.pop('username', None) 27 return redirect(url_for('index')) 28 29 # set the secret key. keep this really secret: 30 app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' 31 32 基本使用

1 pip3 install Flask-Session 2 3 run.py 4 from flask import Flask 5 from flask import session 6 from pro_flask.utils.session import MySessionInterface 7 app = Flask(__name__) 8 9 app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' 10 app.session_interface = MySessionInterface() 11 12 @app.route('/login.html', methods=['GET', "POST"]) 13 def login(): 14 print(session) 15 session['user1'] = 'alex' 16 session['user2'] = 'alex' 17 del session['user2'] 18 19 return "内容" 20 21 if __name__ == '__main__': 22 app.run() 23 24 session.py 25 #!/usr/bin/env python 26 # -*- coding:utf-8 -*- 27 import uuid 28 import json 29 from flask.sessions import SessionInterface 30 from flask.sessions import SessionMixin 31 from itsdangerous import Signer, BadSignature, want_bytes 32 33 34 class MySession(dict, SessionMixin): 35 def __init__(self, initial=None, sid=None): 36 self.sid = sid 37 self.initial = initial 38 super(MySession, self).__init__(initial or ()) 39 40 41 def __setitem__(self, key, value): 42 super(MySession, self).__setitem__(key, value) 43 44 def __getitem__(self, item): 45 return super(MySession, self).__getitem__(item) 46 47 def __delitem__(self, key): 48 super(MySession, self).__delitem__(key) 49 50 51 52 class MySessionInterface(SessionInterface): 53 session_class = MySession 54 container = {} 55 56 def __init__(self): 57 import redis 58 self.redis = redis.Redis() 59 60 def _generate_sid(self): 61 return str(uuid.uuid4()) 62 63 def _get_signer(self, app): 64 if not app.secret_key: 65 return None 66 return Signer(app.secret_key, salt='flask-session', 67 key_derivation='hmac') 68 69 def open_session(self, app, request): 70 """ 71 程序刚启动时执行,需要返回一个session对象 72 """ 73 sid = request.cookies.get(app.session_cookie_name) 74 if not sid: 75 sid = self._generate_sid() 76 return self.session_class(sid=sid) 77 78 signer = self._get_signer(app) 79 try: 80 sid_as_bytes = signer.unsign(sid) 81 sid = sid_as_bytes.decode() 82 except BadSignature: 83 sid = self._generate_sid() 84 return self.session_class(sid=sid) 85 86 # session保存在redis中 87 # val = self.redis.get(sid) 88 # session保存在内存中 89 val = self.container.get(sid) 90 91 if val is not None: 92 try: 93 data = json.loads(val) 94 return self.session_class(data, sid=sid) 95 except: 96 return self.session_class(sid=sid) 97 return self.session_class(sid=sid) 98 99 def save_session(self, app, session, response): 100 """ 101 程序结束前执行,可以保存session中所有的值 102 如: 103 保存到resit 104 写入到用户cookie 105 """ 106 domain = self.get_cookie_domain(app) 107 path = self.get_cookie_path(app) 108 httponly = self.get_cookie_httponly(app) 109 secure = self.get_cookie_secure(app) 110 expires = self.get_expiration_time(app, session) 111 112 val = json.dumps(dict(session)) 113 114 # session保存在redis中 115 # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime) 116 # session保存在内存中 117 self.container.setdefault(session.sid, val) 118 119 session_id = self._get_signer(app).sign(want_bytes(session.sid)) 120 121 response.set_cookie(app.session_cookie_name, session_id, 122 expires=expires, httponly=httponly, 123 domain=domain, path=path, secure=secure) 124 125 自定义Session
第三方session:

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 """ 4 pip3 install redis 5 pip3 install flask-session 6 7 """ 8 9 10 from flask import Flask, session, redirect 11 from flask.ext.session import Session 12 13 14 app = Flask(__name__) 15 app.debug = True 16 app.secret_key = 'asdfasdfasd' 17 18 19 app.config['SESSION_TYPE'] = 'redis' 20 from redis import Redis 21 app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379') 22 Session(app) 23 24 25 @app.route('/login') 26 def login(): 27 session['username'] = 'alex' 28 return redirect('/index') 29 30 31 @app.route('/index') 32 def index(): 33 name = session['username'] 34 return name 35 36 37 if __name__ == '__main__': 38 app.run() 39 40 第三方session
七,蓝图:
蓝图用于为应用提供目录划分:
我们如果项目越做越大,文件就不能只是写到一个文件夹里面,我们需要做拆分,这个时候就需要蓝图来帮我们做这件事,
蓝图代码块:
我们先把文件逻辑整理一下:
在django里面我们的项目目录都是自动生成的,但是我们在flask里面都是需要自己去手动创建的
这里是我们创建目录的规则
创建一个文件夹,作为根目录pro_flask
在根目录里面创建一个文件夹,pro_flask
再创建一个templates文件夹里面存我们的HTML页面
还有views文件夹,存放我们的views视图
在根目录里面创建一个init文件,它是我们的程序一加载就会立即执行的文件
再在根目录里建立一个启动文件run.py

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Blueprint 4 from flask import render_template 5 from flask import request 6 7 ac = Blueprint('account', __name__) 8 @ac.route('/index') 9 def index(): 10 return 'wahaha'

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Blueprint 4 5 blog = Blueprint('blog', __name__) 6 7 @blog.route('/hello') 8 def hi(): 9 return 'hello'

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Blueprint 4 5 user = Blueprint('user', __name__) 6 7 @user.route('/home') 8 def home(): 9 return 'home'

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Flask 4 5 app = Flask(__name__,template_folder='templates',static_folder='statics',static_url_path='/static') 6 aps=Flask(__name__) 7 8 from .views import account 9 from .views import blog 10 from .views.user import user 11 aps.register_blueprint(account.ac) 12 app.register_blueprint(account.ac) 13 app.register_blueprint(blog.blog) 14 app.register_blueprint(user)

1 from pro_flask import aps 2 from pro_flask import app 3 4 5 if __name__ == '__main__': 6 app.run() 7 if __name__ == '__main__': 8 aps.run
这里我们按照route参数里面的值,就能调用我们配置好的那些方法,让页面效果显示出来.
大体的逻辑就是我们要建立一个run.py它要在项目目录的一级里面,然后它要引入我们的二级目录的init文件里面的Flask类所实例化出来的对象,在把run方法启动,就形成了启动文件
在这之前我们的启动项都和我们的视图以及路由在一个文件里面包含着,这里我们就把他们都拆分了,拆分之后我们需要让他们关联上,这个时候就需要我们的蓝图了,blueprint,它作为纽带来帮我们把启动项和视图部分给连接上,我们的视图里面要通过Blueprint类实例化出来一个对象,然后这个对象就像Flask实例化出来的对象那样去使用我们的route方法,在Blueprint类里面也有route方法,再回到我们的init文件里面去把我们的views文件夹里面的视图文件名给引入进来,然后再通过Flask类实例化出来的对象去注册blueprint类在view视图里面所实例化出来的对象,就有点类似于我们的admin里面对于model表的注册一样,这个功能解耦就是在init文件里面需要引入实例化对象,然后进行注册,这个步骤会稍稍有点繁琐,它主要就是把我们的视图和启动项给拆分开,就是为了这个功能的实现,所以把蓝图给引入了,通过它作为中间连接去跟我们的run()和视图关联
我们的蓝图创建流程先把上面的目录结构创建好,然后我们在init文件里面先把Flask引入,再把create_app函数创建好,把return值写上,然后把view视图里面的蓝图实例化对象给引入进来,把它注册上,register_blueprint用来注册蓝图实例化对象,写在create_app函数里面去.
这里既然引入了view视图,那么就需要取到视图里面把代码构建出来,引入蓝图,from flask import blueprints 然后用blueprints实例化出来一个对象(xxx=blueprints.Blueprint('xxx',__name__))跟我们的route连接,去做路由匹配然后就是路由和函数了,
再来就是我们的启动文件,manage.py里面的代码引入我们的init里面的create_app然后用它实例化出来一个对象,用这个对象去到main函数里面调用.run()方法,就可以启动程序了
八,闪现:
message是一个基于Session实现的用于保存数据的集合,其特点是:使用一次就删除

1 from flask import Flask, flash, redirect, render_template, request, get_flashed_messages 2 3 app = Flask(__name__) 4 app.secret_key = 'some_secret' 5 6 7 @app.route('/') 8 def index1(): 9 messages = get_flashed_messages() 10 print(messages) 11 return "Index1" 12 13 14 @app.route('/set') 15 def index2(): 16 v = request.args.get('p') 17 flash(v) 18 return 'ok' 19 20 21 if __name__ == "__main__": 22 app.run()
九,中间件:

1 from flask import Flask, flash, redirect, render_template, request 2 3 app = Flask(__name__) 4 app.secret_key = 'some_secret' 5 6 @app.route('/') 7 def index1(): 8 return render_template('index.html') 9 10 @app.route('/set') 11 def index2(): 12 v = request.args.get('p') 13 flash(v) 14 return 'ok' 15 16 class MiddleWare: 17 def __init__(self,wsgi_app): 18 self.wsgi_app = wsgi_app 19 20 def __call__(self, *args, **kwargs): 21 22 return self.wsgi_app(*args, **kwargs) 23 24 if __name__ == "__main__": 25 app.wsgi_app = MiddleWare(app.wsgi_app) 26 app.run(port=9999)
十,请求扩展:

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from flask import Flask, Request, render_template 4 5 app = Flask(__name__, template_folder='templates') 6 app.debug = True 7 8 9 @app.before_first_request 10 def before_first_request1(): 11 print('before_first_request1') 12 13 14 @app.before_first_request 15 def before_first_request2(): 16 print('before_first_request2') 17 18 19 @app.before_request 20 def before_request1(): 21 Request.nnn = 123 22 print('before_request1') 23 24 25 @app.before_request 26 def before_request2(): 27 print('before_request2') 28 29 30 @app.after_request 31 def after_request1(response): 32 print('before_request1', response) 33 return response 34 35 36 @app.after_request 37 def after_request2(response): 38 print('before_request2', response) 39 return response 40 41 42 @app.errorhandler(404) 43 def page_not_found(error): 44 return 'This page does not exist', 404 45 46 47 @app.template_global() 48 def sb(a1, a2): 49 return a1 + a2 50 51 52 @app.template_filter() 53 def db(a1, a2, a3): 54 return a1 + a2 + a3 55 56 57 @app.route('/') 58 def hello_world(): 59 return render_template('hello.html') 60 61 62 if __name__ == '__main__': 63 app.run()
示例:加上注释的代码块
先来个预热:

1 class Foo(): 2 def __init__(self): 3 self.__name='hello' 4 """ 5 我们给类对象添加属性的时候也可以用这个方法去添加 6 使用self.__属性名=属性值,然后我们要调用的时候就用对象名._类名__属性名去调用 7 """ 8 hi=Foo() 9 v=hi._Foo__name 10 print(v)

1 """ 2 在不改变原函数调用基础上,对函数执行前后的信息进行自定义操作 3 """ 4 import functools 5 6 7 def wapper(func): 8 # @functools.wraps(inner) # 这里我们不能用inner,报错信息显示我们在定义前就调用了局部变量名inner,这是语法所不支持的 9 @functools.wraps(func) # 这里加上了functools就把我们的函数名还成他们自己本来的名字,而不是被我们的装饰器里面的inner所替代 10 def inner(*args, **kwargs): 11 return func(*args, **kwargs) 12 13 return inner 14 15 16 @wapper 17 def index(a1): 18 return a1 + 20 19 20 21 @wapper 22 def order(a2): 23 return a2 + 30 24 25 26 # print(index.__name__) 27 # print(order.__name__) 28 29 30 def xx(yy=23): 31 def xbox(func): 32 def inner(*args, **kwargs): 33 if yy == 23: 34 print('hello') 35 res = func(*args, **kwargs) 36 37 return res 38 39 else: 40 print('you are field ') 41 42 return inner 43 44 return xbox 45 46 47 @xx(yy=23) 48 def index0(name): 49 print(name) 50 # index0('hi') 51 52 53 class File(): 54 def __init__(self,a,b,c,): 55 self.a=a 56 self.b=b 57 self.c=c 58 59 def file(self): 60 ... 61 def obj(self): 62 ... 63 64 zz=File('he','she','them')

1 from types import MethodType,FunctionType 2 3 class Foo(): 4 def fetch(self): 5 ... 6 7 # print(isinstance(Foo.fetch,MethodType)) # False 8 # print(isinstance(Foo.fetch,FunctionType)) # True 9 """ 10 如果是类调用这个函数,那么它就是一个函数, 11 但是如果是类实例化出来的对象调用这个函数,那么它就不是函数了,而是一个方法,对象里面的方法, 12 类调用函数 13 对象调用方法 14 """ 15 fh=Foo() 16 # print(isinstance(fh.fetch,MethodType)) # True 17 # print(isinstance(fh.fetch,FunctionType)) # False 18 19 20 def h1(): 21 ... 22 print(isinstance(h1,MethodType)) 23 print(isinstance(h1,FunctionType))
闪现:

1 from flask import Flask, session, flash, get_flashed_messages, request 2 3 """ 4 first we need to put flash into session ,then we could fetch them out 5 get_flashed_messages 6 original_code is here 7 8 def get_flashed_messages(with_categories=False, category_filter=[]): 9 10 flashes = _request_ctx_stack.top.flashes 11 if flashes is None: 12 _request_ctx_stack.top.flashes = flashes = session.pop('_flashes') \ 13 if '_flashes' in session else [] 14 if category_filter: 15 flashes = list(filter(lambda f: f[0] in category_filter, flashes)) 16 if not with_categories: 17 return [x[1] for x in flashes] 18 return flashes 19 20 """ 21 app = Flask(__name__) 22 app.secret_key = 'sfadf' 23 #这里的密钥是必须要加上的,我们要定义一个固定的字符串,这样做是为了让#我们的cookie中的token能够一直被secret_key验证,从而保证我们的#cookie不会失效,这样cookie中存入的session值也会一直保留,验证可以顺利通过. 24 25 26 @app.route('/we') 27 def index(): 28 flash('in me the tiger', category='wep') # 这里的操作是把我们的数据存入到session里面, 29 flash('sniffs the rose', category='she') 30 flash('hello from outside', category='nobody') 31 return 'index' 32 33 34 @app.route('/she') 35 def root(): 36 data = get_flashed_messages(with_categories=True, category_filter=['she']) 37 print(data) 38 return 'root ' 39 40 41 if __name__ == '__main__': 42 app.run()
请求以及相应:

1 from flask import Flask, render_template, redirect, request, jsonify, make_response 2 import json 3 4 app = Flask(__name__) 5 6 7 @app.route('/index', methods=['GET', 'POST'], redirect_to='/xxx') 8 def index(): 9 """ 10 print(request.method) 11 print(request.args) 12 print(request.form) 13 print(request.cookies) 14 print(request.headers) 15 print(1,request.path) 16 print(2,request.files) 17 print(3,request.values) 18 print(4,request.full_path) 19 print(5,request.script_root) 20 print(6,request.host) 21 print(7,request.host_url) 22 print(8,request.base_url) 23 print(9,request.url) 24 print(10,request.values) 25 跟相应相关的参数都在这里 26 :return: 27 """ 28 29 # obj = request.files['the_file_name'] 30 # obj.save('/var/www/uploads/' + secure_filename(obj.filename)) 31 # print(obj) 32 # return "in me the tiger" 33 # return json.dumps({}) # return jsonify({}) 34 # return render_template('index.html') # 我们只要在这里把前端模板文件名写上, 35 # 然后再在当前文件里面把templates文件夹创建好,它就会自动找到这个文件夹里面的文件去加载执行 36 # return redirect('/xxx') # 这里重定向到另一个地址,我们可以在route里面直接加上参数也一样能达到这个效果 37 # 像这样写app.route('/index',methods=['GET','POST'],redirect_to='/xxx') 38 return 'hello world' 39 40 41 @app.route('/xxx', methods=['GET', 'POST']) 42 def hello(): 43 return 'sniffs the rose' 44 45 46 if __name__ == '__main__': 47 app.run()

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>Title</title> 8 </head> 9 <body> 10 <h2>in me the tiger</h2> 11 </body> 12 </html>
路由:route

1 from flask import Flask 2 import functools # 我们引入它放到装饰器里面是为了还原我们的被装饰的函数的名字 3 4 aps = Flask(__name__) 5 6 7 def wapper(func): 8 @functools.wraps(func) # 如果不加上这个还原我们被装饰的函数的名字,那么,装饰多个函数的时候 9 def inner(*args, **kwargs): 10 print('before') 11 12 return func(*args, **kwargs) 13 14 return inner 15 16 17 @aps.route('/xx', methods=['GET', 'POST']) 18 @wapper 19 def just(): 20 return 'Index' 21 22 23 @aps.route('/order', methods=['GET', 'POST']) 24 @wapper 25 def order(): 26 return 'order' 27 28 29 if __name__ == '__main__': 30 aps.run()

1 # 路由 2 from flask import Flask,render_template,redirect 3 app=Flask(__name__) 4 5 # @app.route('/index',methods=['GET','POST']) # 这里直接把路由写到我们的route里面 6 def index(): 7 return 'hello' 8 9 def order(): 10 return 'world' 11 12 app.add_url_rule('/order',view_func=order) # 这种写法就类似于我们的django里面的url+视图,只不过是格式有点区别 13 app.add_url_rule('/index',view_func=index) 14 if __name__=='__main__': 15 app.run()

1 from flask import Flask, render_template, redirect, url_for, session 2 from werkzeug.wrappers import Response 3 app = Flask(__name__) 4 5 6 @app.route('/index', methods=['GET', 'POST'], endpoint='f1') 7 def index(): 8 k1 = url_for('f1') 9 k2 = url_for('login1') # 这里我们用的是反向解析的别名就跟我们的reverse一样,它默认是用我们的函数名, 10 # 如果我们没有定义endpoint就在这里把函数名作为参数加进去,如果我们定义了endpoint就使用我们定义好的 11 k3 = url_for('logout') 12 print(k1, k2, k3) 13 return 'index' 14 15 16 @app.route('/login0', methods=['GET', 'POST'], endpoint='login1') 17 def login(): 18 return 'login' 19 20 21 @app.route('/logout1', methods=['GET', 'POST']) 22 def logout(): 23 return 'logout' 24 25 26 if __name__ == '__main__': 27 app.__call__ 28 app.run()

1 from flask import Flask 2 app=Flask(__name__) 3 # 这里就是加上参数的路由配置,int:就是数字,通配所有数字,只要是数字我们都配在这个int:参数里,必须要有:, 4 # 如果没有:就变成了字符串类型了,你即便传进去的是数字,浏览器传入后端的所有数据都是字符串,在后端这里定义什么类型接收就是什么类型 5 # 如果加上了:然后我们还是用字符串传入后端,就会报错,页面显示不出来 6 @app.route('/index/<int:dt>',methods=['GET',]) 7 def index(dt): 8 print(dt,type(dt)) 9 return 'index' 10 11 if __name__=='__main__': 12 app.run()

1 from flask import Flask, render_template, url_for 2 from werkzeug.routing import BaseConverter 3 4 app = Flask(__name__) 5 6 7 class RegexConverter(BaseConverter): 8 """ 9 自定义url匹配正则表达式 10 """ 11 12 def __init__(self, map, regex): 13 super(RegexConverter, self).__init__(map) 14 """ 15 这里的to_url还有to_python是源码里面的方法, 16 def to_url(self, value): 17 return url_quote(value, charset=self.map.charset) 18 """ 19 self.regex = regex 20 21 def to_python(self, value): 22 """ 23 路由匹配时,匹配成功后传递给视图函数中参数的值 24 :param value: 25 :return: 26 """ 27 return int(value) 28 29 def to_url(self, value): 30 """ 31 使用url_for反向生成url时,传递的参数经过该方法处理,返回的值用于生成url中的参数 32 :param value: 33 :return: 34 """ 35 val = super(RegexConverter, self).to_url(value) 36 return val 37 38 39 app.url_map.converters['jay'] = RegexConverter 40 41 42 # 这里我们要实现自定义加正则匹配的,url传参方式,就需要调用我们的源码里面的to_python还有to_url方法,我们自己重写这两个方法覆盖掉继承的源码的方法 43 # 这都是固定格式 44 @app.route('/index/<jay("\d+"):nt>', methods=['GET', 'POST'], endpoint='index90') 45 def index(nt): 46 print(nt, type(nt)) 47 xx = url_for('index90',nt=9) # 这里反向解析的变量名是我们route里面的endpoint里面的参数, 48 # 后面的参数是我们的route里面的url的参数名, 49 print(xx) 50 return 'hello world' 51 52 53 if __name__ == '__main__': 54 app.run()

1 from flask import Flask, redirect 2 3 app = Flask(__name__) 4 5 6 @app.route('/index', methods=['GET', 'POST']) 7 # 加上redirect_to就是跳转到该路由, 8 9 def index(): 10 return 'in me the tiger' 11 12 13 @app.route('/new', methods=['GET', 'POST'], redirect_to='/index') 14 def new(): 15 return 'sniffs the rose' 16 17 18 if __name__ == '__main__': 19 app.run()

1 from flask import Flask, render_template, Response, redirect 2 3 app = Flask(__name__) 4 app.config['SERVER_NAME'] = 'sogo.com:5000' 5 # 在源码内部我们实现了config['SERVER_NAME']跟subdomain的匹配,我们的subdomain里面的参数要跟下面的函数里面的参数保持一致, 6 # 然后我们输入这个地址和函数的路由得到的是同一个页面 7 8 # 这里是子域名访问,我们在config里面把子域名写上,然后输入上面我们配置项里面定义好的SERVER_NAME里面的值 9 @app.route('/index', subdomain='<user>') 10 def index(user): 11 print(user) 12 return 'in me the tiger, sniffs the rose' 13 14 15 if __name__ == '__main__': 16 app.run()
session:

1 from flask import Flask, session 2 3 app = Flask(__name__) 4 app.secret_key = 'hello' 5 6 7 @app.route('/x2') 8 def index(): 9 session['k'] = 23 10 session['t'] = 40 11 del session['k'] 12 return 'index' 13 14 15 @app.route('/x3') 16 def order(): 17 print(session['t']) 18 return 'in me the tiger' 19 20 21 if __name__ == '__main__': 22 app.run()
配置文件:
建立两个文件夹,分开合作

1 from flask import Flask 2 3 app = Flask(__name__) 4 # 配置文件 5 app.config.from_object("settings.DevelopmentConfig") 6 7 8 @app.route('/index', methods=['GET', "POST"]) 9 def index(): 10 return "in me the tiger" 11 12 13 if __name__ == "__main__": 14 app.run()

1 class BaseConfig(): 2 DEBUG = True # 默认我们的debug是True,就是会自动重启环境,否则我们都需要手动重启, 3 SECRET_KEY = 'aghjksfdsl' 4 5 6 # 生产环境 7 class ProductionConfig(BaseConfig): 8 DEBUG = False # 这里是已经上线的状态,所以我们就把debug设置为False,就是面相用户的状态了 9 10 11 # 开发环境 12 class DevelopmentConfig(BaseConfig): 13 ... 14 15 16 # 测试环境 17 class TestingConfig(BaseConfig): 18 ...
decorator_特殊的装饰器(源码内部封装好的):

1 from flask import Flask, render_template, redirect 2 3 app = Flask(__name__) 4 """ 5 这些request都是我们的源码里面封装好的,我们直接拿过来用就行 6 """ 7 8 9 @app.before_request 10 def emmn(): 11 print('before1') 12 return 'now i see you' # 这里我们设了返回值之后就不会执行接下来的before_request了,就直接走到我们的after_request里面去 13 14 15 @app.before_request 16 def ennm(): 17 print('before2') 18 19 20 @app.after_request 21 def hi(response): 22 print('after1') 23 return response 24 25 26 @app.after_request 27 def ho(response): 28 print('after2') 29 return response 30 31 32 @app.route('/z1') 33 def x1(): 34 print('view1') 35 return 'view1' 36 37 38 # @app.route('/z2') 39 # def x2(): 40 # print('view2') 41 # return 'view2' 42 43 if __name__ == '__main__': 44 app.run()

1 from flask import Flask, request, session, redirect 2 # 通过我们的session加登录验证,我们在before_request函数里面把我们的校验条件 3 app = Flask(__name__) 4 app.secret_key = 'po' # 这个secret_key是验证用的密钥,我们把它设置成一个固定的字符串,这样每一次验证的时候我们的cookie 5 # 里面的token值就会一直被cookie验证,保证我们的cookie一直有效 6 7 8 @app.before_request 9 def check_login(): 10 if request.path == '/login': 11 return None 12 user = session.get('user_info') # 这里是验证条件, 13 if not user: 14 return redirect('/login') 15 16 17 @app.route('/login') 18 def login(): 19 return 'view1' 20 21 22 @app.route('/pl') 23 def index(): 24 session['user_info'] = 'opp' # 我们这里把验证条件加上就可以通过验证了 25 print('view2') 26 return 'index' 27 28 29 if __name__ == '__main__': 30 app.run()
模板_template:

1 from flask import Flask, redirect, render_template, Markup 2 3 app = Flask(__name__) 4 5 6 @app.template_global() 7 def sunshine(a, b): 8 return a + b 9 10 11 def gen_input(value): 12 # 这里就相当于是return了一个input标签,我们用markup就相当于是我们django里面的marksafe一样的效果 13 return Markup("<input value='%s'/>" % value) 14 15 16 @app.route('/who', methods=['GET', 'POST']) 17 def index(): 18 arg = { 19 'h1': 23, 20 'h2': [90, 19], 21 'h3': {'name': 'alex', 'age': 30}, 22 'h4': gen_input, # 这个函数是上面定义好的,在这里放到模板里面用 23 } 24 25 return render_template('index.html', **arg) 26 27 28 if __name__ == '__main__': 29 app.run()

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>base_template</title> 8 </head> 9 <body> 10 11 <div>header</div> 12 <div>{% block content %} 13 {% endblock %} 14 </div> 15 <div>footer</div> 16 </body> 17 </html>

1 {% extends 'base.html' %} 2 3 {% block content%} 4 5 <h2>{{h1}}</h2> 6 <h3>{{h2.0}}    {{h2[1]}}</h3> 7 <!--我们取值在列表里面可以使用.索引值的方式,还可以通过[索引值的方式]--> 8 <h4>{{h3.name}}    {{h3['age']}}</h4> 9 <!--字典里面取值也是通过.键的名字,还有['键的名字']--> 10 <span>{{h3.get('ag','in me the tiger')}}</span> 11 <!--还可以用get,--> 12 <h1>{{h4(37)}}</h1> 13 <h1>{{sunshine(20,30)}}</h1> 14 15 {% endblock %}
视图:
CBV和FBV都在这里

1 from flask import Flask, views 2 3 app = Flask(__name__) 4 import functools 5 6 7 def wapper(func): 8 @functools.wraps(func) # 我们把函数名还原成原生的名字,就可以同时装饰多个函数 9 def inner(*args, **kwargs): 10 print('before') 11 return func(*args, **kwargs) 12 13 return inner 14 15 16 @app.route('/xxx', methods=['GET', 'POST']) 17 @wapper 18 def index(): 19 return 'index' 20 21 22 class IndexView(views.MethodView): 23 methods = ['GET'] 24 25 decorators=[wapper,] 26 def get(self): 27 return 'index.GET' 28 29 def post(self): 30 return 'index.post' 31 32 33 app.add_url_rule('/index', view_func=IndexView.as_view(name="")) # 这里的name是固定属性用法,我们不能不写它, 34 # 它的值可以是空字符串(只能是字符串类型),但是必须要有它 35 36 if __name__ == '__main__': 37 app.__call__ 38 app.run()
中间件:
Middleware

1 from flask import Flask 2 """ 3 first we through the middleware 4 then we do the function 5 """ 6 app = Flask(__name__) 7 app.secret_key = 'wthrtjk' 8 9 10 @app.route('/xx') 11 def index(): 12 return 'index' 13 14 15 class Middleware(): 16 def __init__(self, ol_wsgi_app): 17 self.old_wsgi_app = ol_wsgi_app 18 19 def __call__(self, environ, start_response): 20 print('before') 21 from flask import session, request 22 fp = self.old_wsgi_app(environ, start_response) 23 print('after') 24 return fp 25 26 if __name__ == '__main__': 27 app.wsgi_app = Middleware(app.wsgi_app) 28 app.run()