Flask框架一
框架比较
Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....);
Tornado:2大特性就是异步非阻塞、原生支持WebSocket协议;
Flask:功能和性能虽然不及Django和Tornado,但是Flask的第三方开源组件比丰富;http://flask.pocoo.org/extensions/
Bottle:比较简单;
总结:
都不是我写的!!!不论优劣,不同的工具而已;
小型web应用设计的功能点不多使用Flask;
大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件);
如果追求性能可以考虑Tornado;
Flask介绍
flask是一个短小精悍、可扩展性强的一个Web框架。
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。
werkzeug
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简单使用
from flask import Flask app=Flask(__name__) #创建1个Flask实例 @app.route('/') #路由系统生成 视图对应url,1. decorator=app.route() 2. decorator(first_flask) def first_flask(): #视图函数 return 'Hello World' #response if __name__ == '__main__': app.run() #启动socket
# 1. 装饰器 import functools def auth(func): @functools.wraps(func) def inner(*args,**kwargs): ret = func(*args,**kwargs) return ret return inner @auth def index(): print('index') @auth def detail(): print('detail') print(index.__name__) print(detail.__name__) # 2. endpoint默认是函数名 # 3. 装饰器先后顺序
一、配置文件
模板路径: template_folder='templates'
静态文件路径:static_url_path='/static/'
静态文件引入别名:static_path='/zhanggen'
设置为调试环境:app.debug=True (代码修改自动更新)
设置json编码格式 如果为False 就不使用ascii编码:app.config['JSON_AS_ASCII']=False
设置响应头信息Content-Type app.config['JSONIFY_MIMETYPE'] ="application/json;charset=utf-8" (注意 ;charset=utf-8)
给你一个路径 “settings.Foo”,可以找到类并获取去其中的大写的静态字段。
settings.py class Foo: DEBUG = True TEST = True
import importlib path = "settings.Foo" p,c = path.rsplit('.',maxsplit=1) m = importlib.import_module(p) cls = getattr(m,c) print(cls) #<class 'settings.Foo'> print(dir(cls)) #['DEBUG', '__call__', '__class__', '__delattr__', '__dict__', # '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', # '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', # 如果找到这个类? for key in dir(cls): if key.isupper(): print(key,getattr(cls,key))#DEBUG True
1. 配置文件 flask.py中 app.config.from_object("settings.DevelopmentConfig")
print(app.config) flask中默认的配置文件
settings中 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
二、路由系统
1.动态路由(url传参)
@app.route('/user/<name>')
from flask import Flask app=Flask(__name__) @app.route('/<name>') #设置url传参数 http://127.0.0.1:5000/zhanggen def first_flask(name): #视图必须有对应接收参数 print(name) return 'Hello World' #response if __name__ == '__main__': app.run() 接收字符串类型参数
@app.route('/post/<int:age>')
#接收整型数字参数 app=Flask(__name__) @app.route('/<int:age>/') #设置url传参数 http://127.0.0.1:5000/18/ def first_flask(age): #视图必须有对应接收参数 print(age) return 'Hello World' #response if __name__ == '__main__': app.run(
@app.route('/post/<float:salary>')
#接收浮点型型数字参数 app=Flask(__name__) @app.route('/<float:salary>/') #设置url传参数http://127.0.0.1:5000/2345555.8889/ def first_flask(salary): #视图必须有对应接收参数 print(salary) return 'Hello World' #response if __name__ == '__main__': app.run()
@app.route('/post/<path:path>')
# 接收URL链接类型参数 app=Flask(__name__) @app.route('/<path:url>/') #设置url传参数:http://127.0.0.1:5000/http://www.baiu.com/ def first_flask(url): #视图必须有对应接收参数 print(url) return 'Hello World' #response if __name__ == '__main__': app.run()
2、指定允许的请求方法(默认GET)
@app.route('/login', methods=['GET', 'POST'])
# 指定允许的请求方法 app=Flask(__name__) @app.route('/<path:url>/',methods=['get']) #只允许get请求 def first_flask(url): print(url) return 'Hello World' #response if __name__ == '__main__': app.run()
#反向生成url from flask import Flask,url_for app=Flask(__name__) @app.route('/<path:url>',endpoint='name1') def first_flask(url): print(url_for('name1',url=url)) #如果设置了url参数,url_for(别名,加参数) return 'Hello World' if __name__ == '__main__': app.run()
4、通过app.add_url_rule()调用路由
#方式2通过app.add_url_rule()方法的方式调用路由 app=Flask(__name__) def first_flask(): return 'Hello World' app.add_url_rule(rule='/index/',endpoint='name1',view_func=first_flask,methods=['GET']) #app.add_url_rule(rule=访问的url,endpoint=路由别名,view_func=视图名称,methods=[允许访问的方法]) if __name__ == '__main__': app.run()
5、扩展路由功能:正则匹配url
from flask import Flask, views, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) class RegexConverter(BaseConverter): """ 自定义URL匹配正则表达式 """ def __init__(self, map, regex): super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): """ 路由匹配时,匹配成功后传递给视图函数中参数的值 :param value: :return: """ return int(value) def to_url(self, value): """ 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 :param value: :return: """ val = super(RegexConverter, self).to_url(value) return val # 添加到flask中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("\d+"):nid>') def index(nid): print(url_for('index', nid='888')) return 'Index' if __name__ == '__main__': app.run() 自定义正则表达式匹配路由
三、视图
FBV
1、给Flask视图函数加装饰器
注意如果要给视图函数加装饰器增加新功能,一点要加在路由装饰器下面,才会被路由装饰器装饰,才能生生成url关系
#给Flask视图加装饰器 #1、定义1个装饰器 def auth(func): print('我在上面') def inner(*args,**kwargs): return func(*args,**kwargs) return inner app=Flask(__name__) @app.route('/',methods=['GET']) @auth #注意如果要给视图函数加装饰器,一点要加在路由装饰器下面,才会被路由装饰器装饰 def first_flask(): print('ffff') return 'Hello World' if __name__ == '__main__': app.run()
CBV
#CBV视图 from flask import Flask,url_for,views #----------------------------------------------------- app=Flask(__name__) #装饰器 def auth(func): print('我在上面') def inner(*args,**kwargs): return func(*args,**kwargs) return inner #-------------------------------------------------------- class IndexView(views.MethodView): #CBV视图 methods=['GET'] #允许的http请求方法(改CBV只允许GET方法) decorators = [auth,] #每次请求过来都加auth装饰器 def get(self): return 'Index.GET' def post(self): return 'Index.POST' app.add_url_rule('/index/',view_func=IndexView.as_view(name='name1')) #(name='name1'反向生成url别名 if __name__ == '__main__': app.run() CBV视图
四、请求和响应相关
from flask import Flask from flask import request from flask import render_template from flask import redirect from flask import make_response app = Flask(__name__) @app.route('/login.html', methods=['GET', "POST"]) def login(): # 请求相关信息 # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host # request.files # obj = request.files['the_file_name'] # obj.save('/var/www/uploads/' + secure_filename(f.filename)) # 响应相关信息 # return "字符串" # return render_template('html模板路径',**{}) # return redirect('/index.html') # response = make_response(render_template('index.html')) # response是flask.wrappers.Response类型 # response.delete_cookie('key') # response.set_cookie('key', 'value') # response.headers['X-Something'] = 'A value' # return response return "内容" if __name__ == '__main__': app.run()
print(request.method) #获取访问方式 GET print(request.url) #获取url http://127.0.0.1:5000/req?id=1&name=wl print(request.cookies) #获取cookies {} print(request.path) # 获取访问路径 /req print(request.args) #获取url传过来的值 ImmutableMultiDict([('id', '1'), ('name', 'wl')]) print(request.args.get("id")) #get获取id 1 print(request.args["name"]) # 索引获取name wl print(request.args.to_dict()) # 获取到一个字典 {'id': '1', 'name': 'wl'} post获取到的参数 print(request.form) # 格式 ImmutableMultiDict([('username', '123'), ('pwd', '123')]) print(request.form.to_dict()) # 格式 {'username': '123', 'pwd': '123'}
request.values 只要是个参数我都要,get和post参数都能拿到
返回json格式
dict = {'k1'"v1}
return json.dumps(dict)
return jsonfy(dict)
from flask import make_response obj = make_response('index') obj.set_cookie('key', 'value') obj.headers['X-Something'] = 'A value' return obj
认证
auth逻辑关系,通过装饰器给每个函数加认证
before_request类似于中间件
五、模板
Flask使用的是Jinja2模板,所以其语法和Django无差别(Django的模板语言参考Jinja2)
1.引用静态文件
方式1:别名引入
<link rel="stylesheet" href="/zhanggen/commons.css">
方式2:url_for()方法引入
<link rel="stylesheet" href="{{ url_for('static',filename='commons.css') }}">
2.模板语言引用上下文对象
变量
<h1>{{user_list}}</h1> <!--变量 -->
循环、索引取值
<ul> {% for user in user_list %} <!--循环 --> <li>{{user}}</li> {% endfor %} {{user_list.0}} <!-- 索引取值--> </ul>
v.name
v['name']
v.get('name',默认)
@app.route('/tpl') def tpl(): context = { 'users':['longtai','liusong','zhoahuhu'], 'txt':Markup("<input type='text' />"), 模板语言中{{txt|safe}} 'func':func #执行函数需要加() } return render_template('tpl.html',**context)
template_global() 全局使用,不用传值,在模板语言中直接使用
@app.template_global() def sb(a1, a2): # {{sb(1,9)}} return a1 + a2 # {{sb(1,9)}}
template_filter()
@app.template_filter() def db(a1, a2, a3): # {{ 1|db(2,3) }} 可以防在if后边做条件 {% if {{ 1|db(2,3) }} %} return a1 + a2 + a3
模板(继承、块、安全、宏定义)
继承和块
- 模板继承 layout.html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>模板</h1> {% block content %}{% endblock %} </body> </html> tpl.html {% extends "layout.html"%} {% block content %} {{users.0}} {% endblock %}
include
include {% include "form.html" %} form.html <form> asdfasdf asdfasdf asdf asdf </form>
宏定义
相当于定义了一个函数,
在全局都可以调用
{% macro ccccc(name, type='text', value='') %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交"> {% endmacro %} {{ ccccc('n1') }} {{ ccccc('n2') }}
安全
安全 - 前端: {{u|safe}} - 后端: MarkUp("<a></a>")
I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我