这篇文章将为大家详细讲解有关什么是Flask框架,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
一、初识Flask
Flask扩展应用扩展包
二、认识werkzurg,Flask最重要的依赖
Python Web 框架工具包 werkzeug
# 引用werkzurg的功能模块 from werkzeug.wrappers import Request,Response from werkzeug.serving import run_simple # 底层的用法 def run(environ,start_response): return [b'abcdefg'] if __name__ == '__main__': run_simple('localhost',4000,run) # 监听端口并执行run函数 # 另一种用法 @Response.application def hello(request): return Response('Hello World!') ''' return到底返回到客户端什么内容? 1、状态码:status code 200,301,404,返回一个响应的客户端的状态码; 2、content-type:告诉客户端用什么方式解析返回的值; 3、其他的返回头信息。 ''' if __name__ == __main__: run_simple('localhost',4000,hello)
三、Flask 使用
3.1、简单的登录
from flask import Flask as fk , request,render_template as render,redirect,session,make_response app = fk(__name__) app.secret_key = 'abckd' # 设置session 的加密值 @app.route('/',methods=['GET','POST']) def index(): if request.method == 'POST': user = request.form.get('user') pwd = request.form['pwd'] if user == 'admin' and pwd == '123': print(user,pwd) return '登录成功!' return render('index.html',h2='你好') # home.add_url_rule('/',view_func=index) #第二种路由的声明方式,必须已“/”开头 if __name__ == '__main__': app.run(debug=True,host='192.168.0.11',port=5000) ''' 执行werkzurg中的run_simple('localhost',4000,hello) 这里只是socket进行了请求监听,当浏览器发起请求后,执行内部的__call__()方法。 '''
3.2、静态文件的处理方法
<!-- 使用静态文件需要删除 <!DOCTYPE html> --> <html> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/index.css" type="text/css"> <!-- javascript引用时必须添加type="text/javascript" --> <script language="javaacript" src="/statics/jquery.min.js" type="text/javascript"></script> <!-- 推荐使用这样加载静态文件 --> <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css"> <!-- url_for(),函数配置静态文件,一定要在Flask类中设置静态文件的路径和别名,蓝图中设置静态文件路径和别名是 不能使用的 --> </head> <body> <h2>index</h2> <h2>{{ h2 }}</h2> <form action="/" method="POST"> <input type="text" name="user" > <input type="password" name="pwd"> <input type="submit" value="提交"> </form> </body>
使用 url_for 函数获取静态资源时,必须在实例化 Flask 对象的时候设置 static_url_path(别名),static_folder(静态文件路径)。
from flask import Flask from .views.index import home def shb(): app = Flask(__name__,static_url_path='/static',static_folder='./public',template_folder='./template') ''' PS: 1、static_folder的路径一定要设置正确。 2、static_url_path的值必须是’/static‘,其他测试无效。 3、url(’static‘,filename='静态文件路径') 第一个值必须是’static‘,其他测试无效。 4、template_folder 配置注意存放路径。 5、蓝图中就不再配置存放静态文件的路径和引用别名了;模板也不用再配置,这里是全局配置。 ''' app.register_blueprint(home,url_prefix="/api") return app
3.3、Flask 简单运用
from flask import Flask,render_template,request,redirect,session app = Flask(__name__) # __name__ 可以修改为任意字符串,并可以传入多个参数 app.secret_key = 'abckd' # 设置session加密多余字符串 # 路由装饰器,必须已“/”开头 @app.route('/login',methods=['GET','POST']) # 定义与路由装饰器匹配的执行函数 def login(): print(request.method) # request 需要导入,获取请求的信息 session['key] = value # 设置session值 session.get('key') # 获取session的值 return render_template('login.html',**{key:value}) #return render_template('login.html',key=value) if __name__ == '__main__': app.run(url,prot)
3.4、Flask 的实现基础
Python Threading 线程模块用法
3.4.1、Threading.local 多线程
作用:为每个线程创建一个独立的空间,使得线程对自己空间中的数据进行操作(数据隔离)。
import threading from threading import local local_obj = local() # 实例化local对象 def task(i): local_obj.xxx = i # 为local对象设置一个参数 print(local_obj.xxx,i) # 获取local对象中的参数 # threading.get_ident() 获取线程的唯一标示 print(threading.get_ident(),i) for i in range(10): t = threading.Thread(target=task,args(i,)) # 创建线程 t.start() # 开始执行线程
3.4.2、根据字典自定义类似Threading.localz
import threading import greenlet # 获取协程信息 DIC = {} def task(i): # 获取协成的唯一标记 # indent = greenlet.getcurrent() # treading.get_ident() 获取线程的唯一标记 indent = treading.get_ident() if indent in DIC: DIC[indent]['xxx'] = i else: DIC[indent] = {'xxx':i} print(DIC[index][xxx],i) # 打印字典中的参数 for i in range(10): t = threading.Thread(target=task,args=(i,)) # 创建线程 t.start() # 开始执行线程
3.4.3、自定义升级版Threading.localz
此版本中协程与线程可以完全的兼容,完成对请求的数据隔离。 为什么需要给线程和协程数据进行隔离? 在多个请求的时候,由于每个请求的信息不相同,所以需要对不同的请求信息进行分类管理(数据隔离),从而防止数据混乱; 这样在需要使用视图函数取得用户请求信息的时候,才能根据不同的信息进行取值和修改。
import threading import time try: import greenlet # 获取协程信息 get_indent = greenlet.getcurrent except Exception as e: get_indent = threading.get_ident class local(object): # DIC={} def __init__(self): # pass object.__setattr__(self,'DIC',{}) # 通过父类的方法设置类属性 def __getattr__(self,item): indent = get_indent() if indent in self.DIC: return self.DIC[indent].get(item) else: return None def __setattr__(self,key,value): indent = get_indent() if indent in self.DIC: self.DIC[indent][key] = value else: self.DIC[indent]= {key:value} obj = local() # 类在实例化的时候运行__init__()方法 ''' obj.xx # 对象.方法的时候运行__getattr__()方法,并且把xx当参数传入 obj.xx = 123 # 对象.方法赋值的时候运行__setattr__()方法,并且把xx和123当参数传入 ''' def task(i): obj.xxx = i time.sleep(2) print(obj.xxx,i) for i in range(10): t = threading.Thread(target=task,args=(i,)) # 创建线程 t.start() # 开始执行线程
3.4.4、Flask简单执行流程
3.4.4.1、Flask 的基本执行流程
封装 requestContext 对象, full_dispatch_request(视图函数 执行), response返回 从app.run() 开始 -->> Flask的__call__方法-->> wsgi_app (封装RequestContext(request,session)对象到 localstack) -->> full_dispatch_request(视图函数 执行) -->> 执行扩展(before_request) ,触发信号 -->> 获取response -->> pop reqeust、session -- >> 结束
3.4.4.2、Flask 源码执行顺序
(1)threading local 和 flask的自定义local对象 - 基于本地线程 可以实现线程隔离。 (2)请求到来 封装 ctx = RequestContext(request,session) ctx -- 放入 Local __storage__ { 'id':{stack:[ctx]} } (3)执行视图 导入 request print(reqeust) -- >> localproxy __str__ reqeust.method -- >> localproxy __getattr__ reqeust + 1 -- >> localproxy __add__ 调用_lookup_req_object函数,去local中的ctx中获取reqeust session (4)请求结束 ctx.auto_pop ctx 从 local 中移除
四、Flask中的方法
Flask request 属性详解
# Flask 中的模块 from flask import Flask,render_template,request,redirect,session request.method # 获取请求的方法 request.args # 获取get请求的数据 request.args.get('') # 获取get请求指定的值 request.form # 获取post请求的数据 request.form.get('') # 获取post请求指定的值 files = request.files.get('') # 获取POST上传的文件信息 files.filename # 获取上传的文件名 files.stream # 获取上传文件的内容 files.save('文件路径','上传文件的内容',) # 保存上传文件到本地 ''' session 的处理 flask 放入的是加密cookie中的,继承了字典的所有功能; flask读取cookie中session对应的值,将该值解密并反序列化成为字典,供视图函数使用; 当请求结束时,flask会读取内存中字典的值,进行序列化并加密,写入到浏览器cookie中。 ''' session['key'] = value # 为session赋值 保存在浏览器的cookie中 session.get('') # 获取session的值 del session['key'] # 删除 # 设置响应头 rst = make_response('aaa') # 设置返回加密 rst.headers['Access-Control-Allow-Origin'] = '*' # 允许请求的域名 rst.headers['Access-Control-Allow-Methods'] = 'POST' # 允许POST请求 # Flask() 配置项 import_name, # 文件名称 static_url_path=None, # 静态文件别名 static_folder='static', # 静态文件路径 static_host=None, host_matching=False, subdomain_matching=False, template_folder='templates', # 模板文件路径 instance_path=None, # 实例文件路径 instance_relative_config=False, # 实例配置文件相对路径 root_path=None # 根文件路径 # Flask 配置文件 app.config['ENV'] 获取内部的值 'ENV': None, 'DEBUG': None, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), # session保留时间 'USE_X_SENDFILE': False, 'SERVER_NAME': None, # 设置域名 xxx.com 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, # session以什么方式保存保留时间 'MAX_CONTENT_LENGTH': None, # 上传文件大小限制 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'SQLALCHEMY_DATABASE_URI' : 'mysql://root:root@127.0.0.1/mysql', # 配置数据库连接 'SQLALCHEMY_TRACK_MODIFICATIONS' : False, # 自定义配置 'SERVER_PORT': 8000, # 端口 'IP_PATH': '127.0.0.1',# 访问链接
# 绑定二级域名的方法 app.url_map.default_subdomain = 'www' # 设置域名前缀 app.config['SERVER_NAME'] = 'testing.com' # 设置域名 app.register_blueprint(public, subdomain='static') # 设置静态文件 PS:要指定默认的域名(app.url_map.default_subdomain ),不然无法访问; SERVER_NAME、app.url_map.default_subdomain 在开发环境是不能加,会报404。
五、Flask配置文件
5.1、通过字符串获取 Class 并运行(反射)
hasattr、setattr、getattr 解释
hasattr(object, name) 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
class test(): name="xiaohua" def run(self): return "HelloWord" t=test() hasattr(t, "name") #判断对象有name属性 #输出:True hasattr(t, "run") #判断对象有run方法 #输出:True
setattr(object, name, values) 给对象的属性赋值,若属性不存在,先创建再赋值。
getattr(object, name[,default]) 可以取出来某个属性,这个属性如果是一个字段,就得到字段的值了,如果是一个方法,就得到这个方法的指针了,然后可以根据方法的指针来调用方法。
class test(): name="xiaohua" def run(self): return "HelloWord" t=test() setattr(t,'max',30) #在对象中设置max属性 getattr(t, "name") #获取name属性,存在就打印出来。 #输出:'xiaohua' getattr(t, "run") #获取run方法,存在就打印出方法的内存地址。 #输出:<bound method test.run of <__main__.test instance at 0x0269C878>> getattr(t, "run")() #获取run方法,后面加括号可以将这个方法运行。 #输出:'HelloWord' getattr(t, "age") #获取一个不存在的属性。 ''' Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: test instance has no attribute 'age' ''' getattr(t, "age","18") #若属性不存在,返回一个默认值。 #输出:'18'
5.2、Flask配置文件的原理
# settings.py 文件 class Foo(object): DEBUG = True
# 获取settings.py中类的项目 import importlib path = 'settings.Foo' p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) # 如果找到这个类 for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) # 输出 # DEBUG True
5.3、Flask 三种加载配置方式
在 Flask 程序运行的时候,可以给 Flask 设置相关配置,比如:配置 Debug 模式,配置数据库连接地址等等,设置 Flask 配置有以下三种方式:
从配置对象中加载(常用):app.config.from_object()
从配置文件中加载:app.config.from_pyfile()
从环境变量中加载(了解):app.config.from_envvar()
以下演练以设置应用程序的 DEBUG(调试模式) 为例,设置应用为调式模式这后,可以实现以下功能。
5.3.1、配置文件
创建配置文件 config.py,在配置文件中添加配置。
app.config.from_pyfile('config.py')
5.3.2、环境变量(了解)
加载指定环境变量名称所对应的相关配置
app.config.from_envvar('FLASKCONFIG') # 读取配置 app.config.get()
在视图函数中使用 current_app.config.get() 注:Flask 应用程序将一些常用的配置设置成了应用程序对象的属性,也可以通过属性直接设置/获取某些配置:app.debug = True
5.3.3、Flask配置文件的原理
# settings.py 文件 class Foo(object): DEBUG = True
# 获取settings.py中类的项目 import importlib path = 'settings.Foo' p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) # 如果找到这个类 for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) # 输出 # DEBUG True
5.4、配置对象加载配置
''' app.config # 获取配置文件对象 app.config['ENV'],app.config['ENV'] = ‘aaa' # 获取和设置配置文件的值 app.config.from_object(‘settings.Foo’) # 通过外部文件引入配置文件 ''' # settings.py 文件 class 类名: 配置文件key = 配置文件value # 使用 settings.py 文件,文件名任意。 app.config.from_object(‘settings.类名’)
# 主程序运行文件 from flask import Flask from .views.account import bpaccount # 导入视图 from .views.code import bpcode app = Flask(__name__) app.config.from_object("settings.TestingConfig") #导入配置文件配置类 # 读取配置文件 app.config['DEBUG'] def create_app(): app=Flask(__name__) app.config.from_object("settings.DevelopmentConfig")#导入配置文件配置类 app.register_blueprint(bpaccount) app.register_blueprint(bpcode) return app
# settings文件 class Config(object): # 公共的配置类 DEBUG =False SECRET_KEY="ADAFA" # 不同应用环境的不同配置类 class ProductionConfig(Config): DEBUG = False class DevelopmentConfig(Config): DEBUG = False class TestingConfig(Config): TESTING=True
六、路由系统
6.1、endpoint 的使用
from flask import Flask, url_for app = Flask(__name__) # endpoint 根据名字反向生成URL '/index' 。如果不设置默认为函数名 url_for( 'index') @app.route('/home',methods=['GET'],endpoint='n1') def index(): print(url_for('n1',name=124)) # 反向生成的URL return 'Index' # app.add_url_rule('/home',view_func=index,methods=['GET'],endpoint='n1') # 第二种定义路由的方法 if __name__ == '__main__': app.run(debug=True) # 修改自动重启Flask ''' url_for('n1',name=124) 输出:/home?name=124 '''
6.2、路由传参
''' 动态路由: /index/<int:nid> 只接收整数 /index/<float:nid> 接收浮点数 /index/<name> 接收字符串,自定义 /index/默认为字符串 ''' from flask import Flask,request,render_template as render,redirect,session,make_response as response,url_for app = Flask(__name__,static_url_path='/static/') @app.route('/<int:nid>',methods=['GET','POST']) # @app.route('/<aname>/<int:aid>',methods=['GET','POST']) def index(nid): print(url_for('index',nid=777)) # print(url_for('index.n1',aname=aname,aid=aid)) if request.method == 'POST': user = request.form.get('user') pwd = request.form.get('pwd') if user == 'admin' and pwd == '123': return render('index.html',success='提交成功!') return render('index.html',h2='首页') if __name__ == '__main__': app.run() ''' 输出:/index/777 '''
6.3、 route() 参数
rule # URL规则 view_func # 视图函数名称 methods=['GET'] # 请求的方式 endpoint=None # 名称用于反向生成URL,即:url_for('名称') strict_slashes=None # 对URL最后的 ‘/’ 符号是否严格要求 True:严格要求 False:不严格要求 redirct_to='/new/<int:nid>' # 重定向 app.config['SERVER_NAME'] = ‘主域名’ subdomain='url' # 配置主域名下子域名访问地址,写入'<username>'表示任意子域名
6.4、自定义正则
from flask import Flask,render_template as render,url_for from werkzeug.routing import BaseConverter app = Flask(__name__,static_url_path='/static',static_folder='static') # 自定义正则转换器 class RegexConverter(BaseConverter): def __init__(self, map, *args):# map 路由传入的路径集合 super(RegexConverter, self).__init__(map) # 将接受的第1个参数当作匹配规则进行保存 self.regex = args[0] def to_python(self, value):# 正则匹配URL时触发 return int(value) # value为匹配到的值 def to_url(self, value): # 方向生成URL触发 val = super(RegexConverter, self).to_url(value) return val # url_for() nid 的值 # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: reg app.url_map.converters['reg'] = RegexConverter @app.route('/<reg("\d+"):nid>',methods=['GET','POST']) def index(nid): print(url_for('index',nid=222)) return render('index.html',h2='index') if __name__ == '__main__': app.run()
6.5、浏览器请求URL,Flask视图函数访问流程
6.5.1、循环引用的执行流程
6.5.2、找不到视图函数的解释
为什么循环引用后,无法找到视图函数?
在上图中执行流程中执行了两次 app = Flask(__name__),第一次在fisher主执行流程时,app被赋值一次,但是在book引用fisher主执行文件以后再次执行了 app = Flask(__name__),这样fisher主执行流程的app被后执行的book引用app所覆盖,所以当book引用中流程执行到 if 跳到主执行流程继续执行时, app 已经是 book 模块的赋值,因此就会找不到视图函数。
可以通过 id() 打印app的内存地址来查看两个app是否是同一个app。
七、FBV 视图
FBV 视图:利用函数与路由建立关联,实现请求响应的控制。 CBV 视图:通过定义类的方式来建立视图与路由的关联。
# CBV视图 from flask import Flask,views app = Flask(__name__,static_url_path='/static',static_folder='static') class UserViews(views.MethodView): methods = ['GET'] # 设置请求方式 decorators = [] # 设置装饰器(全部) def get(self,*args,**kwargs): return 'GET' def POST(self,*args,**kwargs): return 'POST' app.add_url_rule('/index',None,UserViews.as_view('uuu')) if __name__ == '__main__': app.run()
7.1、请求相关request
下面是request可使用的属性,其中'*'是比较常用的。 *form 一个从POST和PUT请求解析的 MultiDict(一键多值字典)。 *args MultiDict,要操作 URL (如 ?key=value )中提交的参数可以使用 args 属性: searchword = request.args.get('key', '') *values CombinedMultiDict,内容是form和args。 可以使用values替代form和args。 *cookies 顾名思义,请求的cookies,类型是dict。 stream 在可知的mimetype下,如果进来的表单数据无法解码,会没有任何改动的保存到这个·stream·以供使用。 很多时候,当请求的数据转换为string时,使用data是最好的方式。这个stream只返回数据一次。 *headers 请求头,字典类型。 *data 包含了请求的数据,并转换为字符串,除非是一个Flask无法处理的mimetype。 *files MultiDict,带有通过POST或PUT请求上传的文件。 environ WSGI隐含的环境配置。 *method 请求方法,比如POST、GET。 path .script_root .url .base_url .url_root 如果用户请求如下URL: http://www.example.com/myapplication/page.html?x=y
以上的参数内容如下:
is_xhr 如果请求是一个来自JavaScript XMLHttpRequest的触发,则返回True,这个只工作在支持 X-Requested-With头的库并且设置了XMLHttpRequest。 blueprint 蓝本名字。 endpoint endpoint匹配请求,这个与view_args相结合,可是用于重构相同或修改URL。当匹配的时候发生异常,会返回None。 get_json(force=False, silent=False, cache=True) json 如果mimetype是application/json,这个参数将会解析JSON数据,如果不是则返回None。 可以使用这个替代get_json()方法。 max_content_length 只读,返回MAX_CONTENT_LENGTH的配置键。 module 如果请求是发送到一个实际的模块,则该参数返回当前模块的名称。这是弃用的功能,使用blueprints替代。 on_json_loading_failed(e) routing_exception = None 如果匹配URL失败,这个异常将会/已经抛出作为请求处理的一部分。这通常用于NotFound异常或类似的情况。 url_rule = None 内部规则匹配请求的URL。这可用于在URL之前/之后检查方法是否允许(request.url_rule.methods) 等等。 默认情况下,在处理请求函数中写下 print('request.url_rule.methods', request.url_rule.methods) 会打印: request.url_rule.methods {‘GET’, ‘OPTIONS’, ‘HEAD’} view_args = None 一个匹配请求的view参数的字典,当匹配的时候发生异常,会返回None。
7.2、响应相关
from flask import Flask,make_response as response,jsonify,render_template as render,redirect ''' make_response 封装所有形式的返回响应体,并可以设置返回响应头 res = response(render('index.html',**{'k1':'v1'})) return res 返回响应体 return '' 返回字符串 return jsonify({'k1':'v1'}) 返回json字符串 return render('index.html',**{'k1':'v1'}) 返回一个文件 return redirect('http://www.baidu.com') 返回重定向URL ''' app = Flask(__name__,static_url_path='/static/') app.secret_key = 'abck' @app.route('/',methods=['GET','POST']) def index(): res = response('index.html') # 封装了返回字符串响应体 res.headers['xxx'] = 123 # 设置返回响应头 res.set_cookie = 321 # 设置cookies return res # 返回请求体,请求头, if __name__ == '__main__': app.run()
7.3、before_request 装饰器
from flask import Flask,make_response as response,jsonify,render_template as render,redirect,request app = Flask(__name__,static_url_path='/static/') # app.before_request后面的函数,在所有函数执行前执行。 # app级中app.before_request(函数名)直接使用。 # 蓝图中使用装饰器的方式 @app.before_request def func(): if request.path == '/index': return None return '返回值' # 返回值不是None,不再往后执行,直接返回return的值 # 返回None,才往后执行其他,这里执行index函数 @app.route('/',methods=['GET','POST']) def index(): res = response('index.html') # 封装了返回字符串响应体 res.headers['xxx'] = 123 # 设置返回响应头 res.set_cookie = 321 # 设置cookies return res # 返回请求体,请求头, if __name__ == '__main__': app.run()
八、模板渲染
Flask 模板详解
8.1、基本语句的使用
# 字符串,字典,列表等基本数据类型,都可以通过python本来的方法操作。 {{ 属性名.0 }} {{ 属性名[0] }} {{ 属性名() }} # html标签转换 {{ html标签|safe }} from flask import Markup Markup('<h2>h2标签</h2>') # 设置默认 {{ 属性名|default('你好') }}
8.2、设置全局模板函数
# 设置全局所用的函数 @app.template_global() def sb(a1,a2): return a1 + a2 # 使用:{{ sb(a1,a2) }} # 过滤filter 的使用 @app.template_filter() def sb(a1,a2,a3): return a1 + a2 + a3 # 使用:{{ a1|sb(a2,a3) }}
8.3、模板的继承
模块:{% block content %}{% endblock %} 模板文件: <html> <head> <meta charset="UTF-8"> <title>首页</title> <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css"> </head> <body> <div> {% block content %}{% endblock %} <a href="{{ url_for('admin.index',id=1234)}}">url_for跳转带参数</a> </div> </body> </html> ---------------------------------------------------------------------------------------- <!-- 导入模板文件 --> {% extends './template.html' %} {% block content %} <h2> 你好 </h2> {{ h2 }} {% endblock %} 调用模块: 需要使用模块文件的引入: {% extents '模板文件' %} 模块代码: {% block content %} <h2> 你好 </h2> {{ h2 }} {% endblock %} ------------------------------------------------------------------------------------- 导入模板:{% include '模板文件' %} 宏定义:{% macro ccc(name,type='text',value='') %} # 相当于定义def 函数 <input type="{{ type }}" name="{{ name }}"/> <input type="submit" value="提交"/> {% endmacro %} 使用宏:{{ ccc('n1') }}
8.4、url_for生成静态文件URL连接
''' # 常规构造静态文件链接 1.包含可变部分的动态路由,url_for(endpoint,_external=True,**kwargs)以视图函数端点名和可选参数作为参数, 当_external为True时返回url绝对路径,否则返回相对路径 2.url_for(endpoint,_external=True,**kwargs)中可以为动态静态文件部分传递参数, 如url_for('.static',_external=True,filename='js/html5shiv.min.js'), 返回的url是http://localhost/static/js/html5shiv.min.js ''' # 不在蓝图中使用 url_for 构建静态文件路径 # http://localhost/static/js/fixes/html5shiv.min.js print url_for('static', filename='js/fixes/html5shiv.min.js', _external=True) ''' PS:蓝图中endpoint必须加上当前命名空间前缀表示当前命名空间,如定义的main蓝图,必须如下使用 url_for('main.static',_external=True,filename='js/html5shiv.min.js') ''' # 蓝图中使用url_for构建反向连接时必须添加蓝图名 # http://localhost/static/js/fixes/html5shiv.min.js print url_for('.static', filename='js/fixes/html5shiv.min.js', _external=True) print url_for('main.static', filename='js/fixes/html5shiv.min.js', _external=True)
8.5、错误页面设置
定义错误页面用装饰器 @app.errorhandler() 来完成,在定义的过程中必须遵循的是在 Flask 直接实例化下定义,不然会定义不成功。
# _*_ coding:utf-8 _*_ from flask import Flask, render_template as render app = Flask(__name__) @app.errorhandler(404) def page_not_found(error): return render('/home/404.html'), 404
九、Flash和特殊装饰器
9.1、flash 消息闪现
在使用 flash() 时会使用到session,所以需要在配置文件中配置 SECRET_KEY。
from flask import flash,get_flashed_messages flash('',category='数据分类属性') # 设置 flash('Error',category='error') get_flash_messages() # 获取 get_flash_messages(category_filter=['数据分类属性']) # 通过分类获取 ''' flash 实现原理: flash基于session来处理内容,先将flash('')中的值存入session中,再通过session的pop移除,达到用一次就消失的效果。 ''' # session自己实现 session.pop('属性名')
HTML中获取 flash() 信息
在模板引擎中怎样定义一个变量;通过关键字 set 定义一个变量。category_filte 过滤返回的类别。
{% set messages = get_flash_messages(category_filter=["error"]) %}
Flask消息闪现文档
9.2、Flask中间件
9.2.1、特殊装饰器
#设置全局模板函数 @template_global() @template_filter() # app.route视图函数执行前执行,只运行第一次 @app.before_first_request def x1(): print('before_first') # app.route视图函数执行前执行,多个谁先定义谁先执行 @app.before_requesr def x2(): print('before') # app.route视图函数执行后执行,必须有参数和返回值,多个谁后定义谁先执行 @app.after_request def x3(response): print('after') return response #定义404 @app.errorhandler(404) def not_fourd(arg): return '404'
9.2.2、中间件
''' Flask的中间件需要通过自定义方法,去替换源码中的相关方法,利用在程序获得请求时才运行__call__()的特性, 来创建中间件,从而完成中间件的功能。 ''' class Middleware(object): def __init__(self, old): self.old = old def __call__(self, *args, **kwargs): print('前') ret = self.old(*args, **kwargs) print('后') return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app)
十、蓝图
为开发者提供一个目录结构,让开发更规范,可以将特殊装饰器加到蓝图中,并根据不同的返回内容设置不同的域名前缀。
为什么flask的根目录不是第一个flask03,而是第二个flask03?
因为在对 Flask(__name__) 进行实例化时,__name__ 所获取的值决定了Flask根目录的位置。
10.1、蓝图的基本模型
10.1.1、主路由视图函数
__init__.py
from flask import Flask # 导入定义的蓝图模块 from .views.index import n def app_view(): app = Flask(__name__,) # 注册,url_prefix指定打开URL的访问集 http://127.0.0.1/app/1 http://127.0.0.1/app/2 app.register_blueprint(n,url_prefix='/app')# 添加了url_prefix 模板文件静态文件也需要添加'/app' return app
app.py
from flask03 import app_view app = app_view() print(app) if __name__ == '__main__': app.run()
10.1.2、分路由视图函数
index.py
#coding:utf8 from flask import Blueprint # ps:蓝图名不能与视图函数名一致 n = Blueprint('index',__name__,template_folder='../xxx', static_folder='../statics',static_url_path='/statics') ''' 在蓝图中,必须带上“蓝图函数.endpoint名” url_for('index.n1',name=name) url_for('.n1',name=name) ''' @n.route('/home/<name>',methods=['GET'],endpoint='n1') def index(name): print(name) print(url_for('index.n1',name=name)) return 'home' ''' 访问域名:http://127.0.0.1:5000/api/home/123 输出:“name”:123 “url_for('index.n1',name=name)”:/api/home/123 '''
10.2、大项目蓝图目录结构
十一、Flask上下文管理
11.1、Flask执行顺序
上下文管理的内容: request、session、app、g 1、客户端请求到来时,会将request/session封装到一个对象 RequestContext(self,environ)中(其中self为app对象, environ为客户端请求的原始数据); ctx=RequestContext(self,environ) 封装了 request/session 2、将含有request/session的对象打包,根据线程/协程的唯一标识,作为字典存放在一个 “空间中”(线程/协程唯一标识作为Key,RequestContext对象作为Value), { 线程/协程唯一标识:{ctx:RequestContext对象} .... } 3、视图函数运行过程 from flask import request,session request.method 当有请求过来时,通过线程/协程唯一标识找到,存放在空间中的RequestContext对象,再通过对象找到封装其中的 request/session,最后找到属性.method。 4、请求结束 session保存到浏览器cookie中,并移除字典中的数据,从而结束请求。
11.2、偏函数
import functools def index(a1,a2): return a1+a2 # 函数常规的用法 a = index(12,20) print(a) ''' 利用 functools 模块实现偏函数; 偏函数只要传入一个值,其他的值自动传入 ''' new_func = functools.partial(index,666) a1 = new_func(34) print(a1)
11.3、上下文:执行流程
request 请求执行流程
11.4、上下文session
Flask session 的请求流程
十二、Flask 中的 localProxy 方法
local:维护保存在__storage__字典中的线程/进程;
localStack:视图系统通过其操作local维护的__storage__字典;
localProxy:它的作用主要是帮助 request 获取当前应用的HTTP请求信息,伴 request 运行和消失的。
class LocalProxy(object): def __init__(self): pass def __getattr__(self): pass def __setattr__(self): pass def __getitem__(self): pass lp = LocalProxy()
十三、Flask g变量
1、g作为flask程序全局的一个临时变量,充当着中间媒介的作用,我们可以通过它传递一些数据;
2、g保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别;
3、g对象在一次请求中的所有代码任何地方,都是可以使用的。
g.name='abc'
g变量简单应用
1、创建一个utils.py文件,用于测试除主文件以外的g对象的使用
# utils.py #encoding: utf-8 from flask import g def login_log(): print u'当前登录用户是:%s' % g.username def login_ip(): print u'当前登录用户的IP是:%s' % g.ip
2、在主文件中调用utils.py中的函数
#encoding: utf-8 from flask import Flask,g,request,render_template from utils import login_log,login_ip app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' @app.route('/login/',methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: username = request.form.get('username') password = request.form.get('password') g.username = username g.ip = password login_log() login_ip() return u'恭喜登录成功!' if __name__ == '__main__': app.run()
关于什么是Flask框架就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。