特点:短小精悍,支持三方组件,稳定性相对其他框架较差。
web服务端,基于socket制作
wsgi:应用程序网关接口
django使用的是uwsgi
flask使用的是werkzeug(wsgi封装)
在flask中reqeust和session都为公共变量,直接通过flask导入,而不是通过参数传入视图函数
实现原理是:
wsgi处理-》打包成ctx=RequestContext(包含reqeust,session)->ctx.push(将当前请求信息存入栈中)-》视图函数处理-》执行reqeust相关方法时,从栈中获取数据
{__storage__:{线程号:{"stack":[ctx]}},__ident_func__:get_ident}
get_ident为获取线程号的方法名
websocket通信原理
后端
获取请求体中字符串Sec-WebSocket-Key,拿到key
用magic_string字符串与其拼接,使用sha1加密,再用base64加密
拼接响应头,添加Sec-WebSocket-Accept字段,发送给浏览器
前端浏览器
链接服务器,发送请求头,含Sec-WebSocket-Key字段
获取响应头,解密,校验握手是否成功
解密
浏览器send发送数据过来为bytes类型
bytes = decode[i] ^ mask[i%4]
加密
struct.pack("B",length)
struct.pack("!BH",126,length)
struct.pack("!BQ",127,length)
from flask import Flask
app = Flask(__name__) #在该模块中Flask标识,可以传入任意字符串
@app.route('/') #装饰器第一个参数为路由
def index():
return "hello world" # 直接返回字符串到页面上
app.run() # 启动flask
run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
例如:
app.run(host="127.0.0.1",port=9527,debug=True)
debug为true时,每次修改代码后,自动重启服务
@app.route('/hi2',endpoint="hi2",redirect_to="/",methods=("GET","POST"),defaults={"age":22})
def hi2(age):
return redirect('/')
endpoint:函数标识,默认为函数名,在反向解析时使用url_for(‘hi2’)可以解析出url。 当函数重名时,只要endpoint不重名即可
redirect_to:不通过视图函数,直接重定向(永久重定向)
methods:允许请求方法,默认只允许GET,可以传入一个列表或元组
defaults:默认参数,默认传入视图函数的参数,视图函数必须要有参数来接受
strict_slashes:严格匹配,默认值为False,值为True时,地址末尾多一个斜杠也不允许访问
可以使用<>方式添加变量名,同时视图函数也要接受参数,来匹配路由
默认参数类型是字符串
@app.route('/hi//')
def hi(normal,age):
print(normal,age)
return redirect('/')
处理请求有CBV和FBV两种方式
FBV:在视图中,通过函数类处理请求
CBV:在视图中,通过类来处理请求
通常我们使用函数加装饰器方法组成视图函数
@app.route('/')
def index():
return "hello world"
等价于
def index2():
return "hello world1"
app.add_url_rule("/index2",view_func=index2)
view_func为视图函数的函数名
from flask import views
def war(func):
def inner(*args,**argv):
print("inner")
return func(*args,**argv)
return inner
class Index3(views.MethodView):
methods = ["GET","POST"]
decorators = [war]
def get(self):
return "nice get"
def post(self):
return "nice post"
app.add_url_rule(rule="/test",view_func=Index3.as_view(name="index33"))
类需要继承views.MethodView,类中添加相应请求方法的处理函数(get方法请求,就添加名为get的函数)
methods:默认为只允许get方法访问
decorators: 将类中每个函数添加装饰器,每次执行函数时,自动依次执行装饰器
as_view:将类转换为相应视图函数,name为函数标识
from flask import Flask,render_template,redirect,jsonify,send_file
@app.route('/')
def index():
return "hello world"
@app.route("/login")
def login():
return render_template('login.html')
@app.route('/hi')
def hi():
return redirect('/')
@app.route("/hello")
def hello():
return jsonify({"name":"xiaoming","age":16})
@app.route("/web")
def web():
return send_file("./small.png")
直接返回字符串,类似于django的HttpResponse
render_template返回模板,类似于django的render
redirect重定向(默认302临时重定向),和django一样
jsonify返回json字符串,content-Type为Content-Type: application/json
send_file返回一个本地文件,根据文件不同content-Type不同
reqeust为一个全局变量,获取请求信息,所有请求信息经过wsgi处理后转换为键值对形式存入字典中
from flask import request
@app.route('/')
def index():
print(request.method) #返回当前请求方法
print(request.args) #get携带的参数键值对(字典),get取值
print(request.form) #表单提交
request还有url,path等方法
在django和flask中都使用了jinja2语法
变量语法 {{ msg }}
tag标签语法 逻辑代码 {% if %}
遍历
{% for stu in stu_list %}
{% endfor %}
获取字典值时,可以使用下标,[],get方法
{{ student.name }}
{{ student["name"] }}
{{ student.get("name") }}
获取列表值时,可以使用下标方法或传入索引
{{ student[0] }}
{{ student.0 }}
条件判断
{% if session %}
{% elif session1 %}
{% else %}
{% endif %}
示例
{% if student.3 == 'female' %}
{% else %}
{% endif %}
将变量中字符串渲染成标签
{{ msg|safe }}
默认情况,字符串不能直接被渲染成字符串,必须使用safe
过滤器
类似于safe,只不是在后端执行
from flask import Markup
@app.route('/1')
def index1():
text_tag = "我是p标签
"
text_tag = Markup(text_tag)
return render_template("index.html",msg=text_tag)
将字符串转换为标签,在页面上渲染
后端也可以直接向前端传入函数名,前进接受后直接使用
python
def add(a,b):
return a+b
@app.route('/2')
def index2():
return render_template("index.html",add=add)
html
{{ add(1,2) }}
自定义全局函数
python
@app.template_global()
def add_tag(*args):
return sum(*args)
不需要通过参数传入模板,直接在模板中调用
html
{{ add_tag([1,2,3]) }}
自定义全局过滤器
python
@app.template_filter()
def jiou(num):
return "奇数" if num % 2 else "偶数"
html
{{ 5|jiou }}
继承父模板框架,必须卸载最上方
block:在index.html中为占位符,在index2.html中为实际内容
index.html
Title
{% block container %}
默认显示内容,没有block时显示
{% endblock %}
index2.html
{% extends "index.html" %}
{% block container %}
新内容
{% endblock %}1
include:导入代码块,将代码块导入到网页中
index.html
Title
{% include "login.html" %}
login.html
登录
登录
include:用于多个html页面,有相同代码部分,这部分用include导入,比如导入小广告
extends:用户同一主题的页面,用相同主题,只修改block部分,其他部分不变。extends必须写在页面开头,配合block使用。模板继承
创建标签,宏指令
登录
登录
{% macro create_tag(name) %}
{{ name }}
{% endmacro %}
{{ create_tag("xiaoming") }}
{{ create_tag("wanghua") }}
相当于html中的函数,传入参数,执行参数
session和cookie用户信息的缓存,cookie一般存放在用户端,session一般存放在服务端
但是flask原生session是将用户信息存放在cookie中,也就是用户端
from flask import session
app = Flask(__name__)
app.secret_key = "this_is_any_string"
@app.route('/3')
def index3():
session["name"] = "xiaoming" #添加一个session键值对
print(session["name"]) #获取session值
return render_template("test.html")
注意:首先导入session,其次必须要secret_key
session存放在cookie中,键session,值(secret_key经过md5序列化+时间戳+session字典中的键值)
方法一:
使用字典方式设置
from flask import Flask
app = Flask(__name__)
app.config["DEBUG"]=True
方法二:
使用对象方式
obj为类
class obj():
DEBUG:True
SECERT_KEY="1234567890"
app.config.from_object(obj)
在对象中设置值
flask示例初始化配置
app = Flask(__name__)
'''
def __init__(
self,
import_name, #该参数用来标识实例的(用来区分是否是一个实例化对象,request等)
static_url_path=None, #访问静态文件的url 默认等于static_folder
static_folder="static", #静态文件夹
static_host=None, #远程访问静态文件(静态文件夹不在本地)必须和host_matching一起用
host_matching=False,
subdomain_matching=False,
template_folder="templates", #指定模板文件夹
instance_path=None,
instance_relative_config=False,
root_path=None,
):
'''
flask蓝图相当于不能运行的flask实例,用来做插件用
student_add.py
from flask import Blueprint
stu_add = Blueprint("stu_add",__name__)
@stu_add.route("/student_add",methods=("GET",'POST'))
def student_add():
return render_template("student_add.html")
参数一位蓝图实例名,用来区分蓝图与蓝图
参数二蓝图空间标识
注意:蓝图默认static和template和app默认存储位置相同
注册蓝图
main.py
from student_add import stu_add
app.register_blueprint(stu_add.stu_add)
即可使用
蓝图中的视图函数名与app视图函数名相同时不会出错,但url_for反向解析时会报错
flask使用两种装饰器类似于django中的中间件
@app.before_request
def is_login():
white_list = ['/login',]
if request.path in white_list:
return None
if session.get("is_login") and session["is_login"] + 3000*60 > time.time():
return None
else:
return redirect('/login')
@app.after_request
def go(res):
print("after")
return res
可以自定义404错误
@app.errorhandler(404)
def errors(*args):
print(args)
return "没有找到当前页面"
也可以自定义错误页面
flash存一次,取一次后就销毁,不占空间。
通常用来上一个位置使用
from flask import flash,get_flashed_messages
@app.route("/home")
def home():
res = get_flashed_messages()
print(res)
flash("home")
return render_template("home.html",loc = res)
@app.route("/music")
def music():
res = get_flashed_messages()
print(res)
flash("music")
return render_template("music.html",loc = res)