Flask
app = Flask(__name__)框架解析
初始化APP
flask.py
class Flask(object): ''' 全局变量 ''' request_class = Request response_class = Response static_path = '/static' secret_key = None session_cookie_name = 'session' jinja_options = dict( autoescape=True, extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_'] )
request_class变量是一个Request类,Request类继承自werkzeug的Request类。它调用了werkzeug的Request类的构造函数,RequestBase.__init__(self, environ)。然后又初始化了endpoint和view_args两个变量。
response_class变量是一个Response类。继承自werkzeug的Reponse类。且自己初始化了变量 default_mimetype=‘text/html’
static_path是静态文件路径,默认值为/static
secret_key默认值为None
如果设置了secret_key,加密组件使用这个key签名cookies。当你要使用安全cookie,你要把这个key设置成复杂的随机值
session_cookie_name,session的名字为session
jinja_options选项初始化
初始化构造函数:
def __init__(self, package_name): self.debug = False #debug变量为False self.package_name = package_name #一般为__name__,如果以本模块运行,则为__main__;如果是被调用,则为app文件名。 self.root_path = _get_package_path(self.package_name) #获取app的绝对路径 self.view_functions = {} #视图函数 self.error_handlers = {} #错误处理 self.before_request_funcs = [] #HTTP请求之前需要执行的函数 self.after_request_funcs = [] #HTTP请求结束之后,需要执行的函数 self.template_context_processors = [_default_template_ctx_processor] #上下文模板变量:session、g、request self.url_map = Map() #url集合<br> if self.static_path is not None: #self.static_path默认值为'/static',所以默认会把它加入到url_map集合中。Map([<Rule '/static/<filename>' -> static>]) self.url_map.add(Rule(self.static_path + '/<filename>', build_only=True, endpoint='static')) if pkg_resources is not None: target = (self.package_name, 'static') else: target = os.path.join(self.root_path, 'static') self.wsgi_app = SharedDataMiddleware(self.wsgi_app, { self.static_path: target }) self.jinja_env = Environment(loader=self.create_jinja_loader(), **self.jinja_options) self.jinja_env.globals.update( url_for=url_for, get_flashed_messages=get_flashed_messages )
初始化构造函数中,主要定义了一些变量(debug、包名、包路径、视图函数、上下文相关、路由、static路径、模板相关环境)
路由处理
定义路由装饰器
def route(self, rule, **options): #route装饰器,装饰路由的同时,把路由添加进Map,添加视图函数,确保路由和视图函数映射起来 def decorator(f): self.add_url_rule(rule, f.__name__, **options) #Map([<Rule '/hello'(HEAD,GET) -> hello_world>]) self.view_functions[f.__name__] = f #view_functions = {'hello_world':hello_world} return f return decorator<br> def add_url_rule(self, rule, endpoint, **options): options['endpoint'] = endpoint options.setdefault('methods', ('GET',)) self.url_map.add(Rule(rule, **options))
完成url_map和view_functions的初始化,其中Rule是werkzeug提供的工具
app.run()
app启动过程如下:
flask.run() --> werkzeug.run_simple() --> werkzeug.inner() --> werkzeug.serving.make_server() -->serve_forever() -->SocketServer.BaseServer.HTTPServer.serve_forever() #While True:****
# 引入Flask类,Flask类实现了一个WSGI应用 from flask import Flask # app是Flask的实例,它接收包或者模块的名字作为参数,但一般都是传递__name__ # 让flask.helpers.get_root_path函数通过传入这个名字确定程序的根目录,以便获得静态文件和模板文件的目录 app = Flask(__name__) # 使用app.route装饰器会将URL和执行的视图函数的关系保存到app.url_map属性上 # 处理URL和视图函数的关系的程序就是路由,这里的视图函数就是hello_world @app.route('/') def hello_world(): return 'Hello World!' # 使用这个判断可以保证当其他文件引用这个文件的时候(例如“from hello import app”)不会执行这个判断内的代码,也就是不会执行app.run函数。 if __name__ == '__main__': # 执行app.run就可以启动服务了。默认Flask只监听虚拟机的本地127.0.0.1这个地址,端口为5000 # 而我们对虚拟机做的端口转发端口是9000,所以需要制定host和port参数,0.0.0.0表示监听所有地址,这样就可以在本机访问了 app.run(host='0.0.0.0', port=9000) ''' 服务器启动后,会调用werkzeug.serving.run_simple进入轮询,默认使用单进程单线程的werkzeug.serving.BaseWSGIServer处理请求, 实际上还是使用标准库BaseHTTPServer.HTTPServer,通过select.select做0.5秒的“while TRUE”的事件轮询。 当我们访问“http://127.0.0.1:9000/”,通过app.url_map找到注册的“/”这个URL模式,就找到了对应的hello_world函数执行,返回“hello world!”,状态码为200。 如果访问一个不存在的路径,如访问“http://127.0.0.1:9000/a”,Flask找不到对应的模式,就会向浏览器返回“Not Found”,状态码为404 '''
g对象
在flask中,有一个专门用来存储用户信息的g对象,g的全称的为global
g对象在一次请求中的所有的代码的地方,都是可以使用的.
g 作为 flask 程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别
g对象和session的区别
最大的区别
session对象是可以跨request的,只要session还未失效,不同的request的请求会获取到同一个session,
但是,g对象不需要管过期时间,请求一次就g对象就改变了一次,或者重新赋值了一次.
g对象的使用实例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> <table> <tbody> <tr> <td>用户名:</td> <td><input type="text" name="username" placeholder="请输入用户名"></td> </tr> <tr> <td>密码:</td> <td><input type="password" name="password" placeholder="请输入密码"></td> </tr> <tr> <td></td> <td><input type="submit" value="登录"></td> </tr> </tbody> </table> </form> </body> </html>
###########app.py############ from flask import Flask,g,render_template,request from utils import login_log 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') if username == '111' and password == '222':
# 使用g对象 g.username = '111' login_log() return u'登录成功' else: return u'您的用户名或密码错误' if __name__ == '__main__': app.run()
###########utils.py############## from flask import g def login_log(): print('当前登录用户是',g.username)
使用步骤:
1.创建一个utils.py文件,用于测试除主文件以外的g对象的使用
2.在主文件中调用utils.py中的函数