说明:
flask是一个轻量级的web框架,被称为微型框架。只提供了一个高效稳定的核心,其它全部通过扩展来实现。意思就是你可以根据项目需要进行量身定制,也意味着你需要不断学习相关的扩展库。
核心:
WSGI系统、调试、路由
模板引擎(Jinja2,是flask核心开发者人员发开的)
安装:
>: pip install flask
werkzeug简介
Flask的socket是基于Werkzeug 实现的
Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。这里稍微说一下, werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等
from werkzeug.wrappers import Request, Response @Request.application def hello(request): return Response('Hello World!') if __name__ == '__main__': from werkzeug.serving import run_simple run_simple('localhost', 4000, hello)
flask的使用
Flask运行的本质:
from flask import Flask # 实例化产生一个Flask对象 app = Flask(__name__) # 装饰器路由 @app.route('/') def index(): return 'ok' if __name__ == '__main__': # 本质是 run_simple(host, port, app, **options) # app() 调用的是Flask的__call__里的wsgi_app方法,返回response app.run()
启动参数
参数 说明
debug 是否开启调试模式,默认为False;开启后会有出错调试信息,文件会自动加载。
threaded 是否开启多线程,默认为Flase。
host 指定主机,默认为’127.0.0.1’,设置为’0.0.0.0’后可以通过IP进制访问
port 指定端口,默认为5000。
启动示例:app.run(debug=True, threaded=True, host=‘0.0.0.0’, port=5555)
响应四剑客 render_template,redirect,jsonify
-
返回字符串
@app.route('/') def index(): # 1 直接返回字符串 return 'ok'
-
返回HTML
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): # 2 返回HTML return render_template('index.html') # 参数: xxx.HTML
-
跳转页面(重定向)
from flask import Flask, redirect app = Flask(__name__) @app.route('/') def index(): # 3 跳转页面 return redirect('/login') # 参数: url @app.route('/login') def login(): return render_template('login.html')
-
返回json数据
from flask import Flask, jsonify app = Flask(__name__) @app.route('/') def index(): # 4 返回json数据 dic = {'name':'xionger', 'age': 20} return jsonify(dic) # 参数: 要序列化的数据
templates(模板层)
1. 创建templates文件夹
2. 文件夹内创建HTML文件
-
视图函数向HTML页面传递数据
# 方式一
@app.route('/') def index(): dic = {'name': 'xionger', 'age': 20} return render_template('index.html', num=100, dic_data=dic)
# 方式二 from flask import Flask, render_template, Markup app = Flask(__name__) def func(t1, t2): return Markup(f'<h1>hahaha{t1}{t2}</h1>') @app.route('/list',methods=['GET']) def list(): return render_template('list.html',html="<h1>hahaha</h1>", func=func) # list.html {{ html|safe }} {{ func(1, 2) }}
-
模板语法
<body> <p>{{ num }}</p> 100 <p>{{ dic_data.name }}</p> xionger <p>{{ dic_data.get('name') }}</p> xionger <p>{{ dic_data['name'] }}</p> xionger </body> <!-- 字典, 列表等数据类型在python中如何使用, 在模板中就如何使用 -->
<!-- 遍历循环 --> <body> <h1>用户列表</h1> <table> {% for k,v in user_dict.items() %} <tr> <td>{{k}}</td> <td>{{v.name}}</td> <td>{{v['name']}}</td> <td>{{v.get('name')}}</td> <td><a href="/detail/{{k}}">查看详细</a></td> </tr> {% endfor %} </table> </body>
<!-- 逻辑判断 --> <body> <h1>用户列表</h1> <table> {% if name %} <h1>Hello {{ name }}!</h1> {% else %} <h1>Hello World!</h1> {% endif %} </table> </body>
配置文件
-
方式一
# 这中方式只能配置两种 app.debug=True app.secret_key="123123"
-
方式二 :使用config字典
app.config['DEBUG']=True
-
方式三: 导入文件(插拔式)
settings.py
# DEBUG = True class Config(object): DEBUG = False TESTING = False DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True
视图函数文件.py
app.config.from_object('settings.DevelopmentConfig')
补充:
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, }
路由系统
@setupmethod def add_url_rule( self, rule, # --> 装饰器里的路由 endpoint=None, # --> 路由别名 view_func=None, # --> 视图函数 provide_automatic_options=None, **options # 用来接收methods等参数的字典 ): if endpoint is None: # 若路由没有起别名 # endpoint = 视图函数的名字 endpoint = _endpoint_from_view_func(view_func) # 将endpoint添加到options里 options["endpoint"] = endpoint # 获取methods的值 methods = options.pop("methods", None) # if the methods are not given and the view_func object knows its # methods we can use that instead. If neither exists, we go with # a tuple of only ``GET`` as default. if methods is None: # methods为空 则默认是GET请求 methods = getattr(view_func, "methods", None) or ("GET",) if isinstance(methods, string_types): raise TypeError( "Allowed methods have to be iterables of strings, " 'for example: @app.route(..., methods=["POST"])' ) methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, "required_methods", ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. if provide_automatic_options is None: provide_automatic_options = getattr( view_func, "provide_automatic_options", None ) if provide_automatic_options is None: if "OPTIONS" not in methods: provide_automatic_options = True required_methods.add("OPTIONS") else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) # endpoint 是视图函数的名字 if old_func is not None and old_func != view_func: raise AssertionError( "View function mapping is overwriting an " "existing endpoint function: %s" % endpoint ) # 若view_functions中有endpoint 则取出赋值给view_func # view_func要么必须有值, 要么endpoint有别名, 最终endpoint的值也会赋值给view_func self.view_functions[endpoint] = view_func # 如果endpoint有别名 view_func = endpoint # 如果endpoint没有有别名 view_func = endpoint(视图函数名字)