# 模板、请求与响应
# jinja2语法
- Flask使用的是Jinja2模板,所以其语法和Django基本无差别,因为templete语法是继承jinjia2
# 1、模板基本数据的渲染
变量 {{..}}
列表 {% for item in List %}<li>{{item}}</li>{% endfor %}
字典 {% for k,v in Dict.items() %}<li>{{k}}{{v}}</li>{% endfor %}
# 2 注意:Markup等价django的mark_safe 用于返回有效的html标签
也可以像django一样使用 {{data|safe}}
>>> from flask import Markup
>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>'
Markup(u'<strong>Hello <blink>hacker</blink>!</strong>')
>>> Markup.escape('<blink>hacker</blink>')
Markup(u'<blink>hacker</blink>')
>>> Markup('<em>Marked up</em> » HTML').striptags()
u'Marked up \xbb HTML'
# 3 像django的simple_tag, filter 一样,传递自定义的函数
局部 -- 局部模板使用
1、局部函数 -- 只能在传入的template中使用,直接定义,传递,在视图函数中定义
def add_num(a,b):
return int(a) + int(b)
2、在视图函数中返回时:
return render_template('..html','add_num':add_num)
3、模板中使用:
{{add_num(1,2)}}
-------------------------------------------------
全局 -- 全局使用
django 的 filter可以当做if条件
需要 @app.template_global()装饰器
def func(a,b,c) --->> 全局temlate使用 {{func(a,b,c)}}
和 @app.template_filter()装饰器
def func(a,b,c) --->> 全局temlate使用 {{a|filter(b,c)}} # 需要管道符
# 4 模板继承
{% extends 'layout.html' %} #模板的继承
{% block body %} #块继承
{% endblock %}
{% include 'asd.html' %} #组件的使用
# 5 定义宏: 相当于定义函数来控制html的内容
一般是用于多次会用到的地方,比如分页;相当于定义了个函数,用的时候调用才行
在需要重用的html中写,paginator.html:
{% macro page(data,url) -%}
{% if data %}
<ul class="pagination pagination-sm no-margin">
<li><a href="{{ url_for(url,page=1) }}">首页</a></li>
{% if data.has_prev %}
<li><a href="{{ url_for(url,page=data.prev_num) }}">上一页</a></li>
{% else %}
<li class="disabled"><a href="">上一页</a></li>
{% endif %}
{% for v in data.iter_pages() %}
{% if v == data.page %}
<li class="active"><a href="{{ url_for(url,page=v) }}">{{ v }}</a></li>
{% else %}
<li><a href="{{ url_for(url,page=v) }}">{{ v }}</a></li>
{% endif %}
{% endfor %}
{% if data.has_next %}
<li><a href="{{ url_for(url,page=data.next_num) }}">下一页</a></li>
{% else %}
<li class="disabled"><a href="">下一页</a></li>
{% endif %}
<li><a href="{{ url_for(url,page=data.pages) }}">尾页</a></li>
</ul>
{% endif %}
{%- endmacro %}
调用:
{% import 'admin/paginator.html' as pg %}
{{ pg.page(page_data,'admin.tag_list') }}
函数的例子:
视图中:
from flask import Flask,redirect,Markup,render_template,make_response
app = Flask(__name__)
# 全局使用
@app.template_filter()
def Filter(a,b,c):
return min(a,b,c)
# 全局使用
@app.template_global()
def Global(a,b,c):
return a + b + c
# 自定义函数 -- 局部
def add_num(a,b):
return int(a) + int(b)
@app.route('/index',endpoint='index',methods=['GET'])
def index():
Dict = {
'List':[1,2,3],
'Dict':{'amy':18,'bob':20},
'Str':'hello',
'add_num':add_num,
'tag':Markup('<a href="#">点击</a>') # 或者在templates中使用 |safe
}
response = make_response(render_template('index.html',**Dict))
return response
if __name__ == '__main__':
app.run()
html中:
<p>hello!</p>
<p>字符串:{{Str}}</p>
<ul>
列表:
{% for item in List %}
<li>
{{item}}
</li>
{% endfor %}
字典:
{% for k,v in Dict.items() %}
<li>
{{k}}{{v}}
</li>
{% endfor %}
</ul>
<p>自定义加法函数:{{add_num(1,4)}}</p>
<p>全局函数global:{{Global(1,4,5)}}</p>
<p>全局函数filter:{{1|Filter(1,4)}}</p>
html标签:{{tag}}
Flask中模板使用函数的两种方法
from flask import Flask, render_template,Markup app = Flask(import_name=__name__) def func1(args): return Markup("<input type='text' value='%s' />" % (args,)) @app.route('/index1') def index3(): return render_template('test.html',ff=func1) if __name__ == '__main__': app.run() #html文件中 <body> <!-- 方式一--> {{ff(12)|safe}} <!--方式二--> {{ff(12)}} </body>
# Flask中的Response相关
Django的响应 Flask响应
1.HTTPResponse("hello") "" 返回str
2.render 响应模板 render_template("html") 返回str
3.redirect("/") redirect("/") 返回str
以上是Web框架的 Response 三剑客
4.send_file() instance 返回文件内容,自动识别文件类型,Content-type中添加文件类型,Content-type:文件类型
#浏览器特性 可识别的Content-type 自动渲染 不可识别的Content-type 会自动下载
5.jsonify() str #返回标准格式的JSON字符串 先序列化JSON的字典,Content-type中加入 Application/json
#例子:
from flask import jsonfy
...
return jsonfy(**dict)
Flask 1.1.1 版本中 可以直接返回字典格式,无需jsonify
# Flask 中的 请求 Request
request.method #获取请求方式
request.form #获取FormData中的数据 也就是所谓的Form标签 to_dict()
request.args #获取URL中的数据 to_dict()
request.json #请求中 Content-Type:application/json 请求体中的数据 被序列化到 request.json 中以字典的形式存放
request.data #请求中 Content-Type 中不包含 Form 或 FormData 保留请求体中的原始 数据 b""
request.files #获取Form中的文件
request.path #请求路径 路由地址
request.url #访问请求的完整路径包括 url参数
request.host #主机位 127.0.0.1:5000
request.cookies #字典获取浏览器请求时带上的Cookie
request.values # 所有的请求参数
#request.values 获取 url 和 FormData 中的数据 敏感地带
request.args.get('id')
request.args.getlist('ids') # 获取多个值
data = request.args
data_dict = data.to_dict() # 通过to_dict() 方法 转化成 字典
from urllib.parse import urlencode,quote,unquote
url = urlencode(data_dict) # 转换成 url
quote -->> url编码
request.headers
request.full_path
request.script_root
request.base_url
request.url_root
request.host_url
request.remote_addr # 获取 ip
request.files # 获取form上传的文件
obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename)) #保存在此,注意我们使用了secure_filename生成一个字符串的名字,以防止文件重名被覆盖
# 定制响应体
使用
make_response
方法给响应体中添加信息,包括响应头和响应体1、我们在使用模板渲染的时候使用render_template,如下: def index(): return render_template('index.html', foo=42) 2、当我们想给响应体/响应头中添加附加信息时,我们将使用make_response def index(): response = make_response(render_template('index.html', foo=42)) response.headers['X-Parachutes'] = 'parachutes are cool' return response 3、response是flask.wrappers.Response类型,可以查看源码,还可以设置其他属性 response.set_cookie('key', 'value') response.delete_cookie('key') response.headers['X-Something'] = 'A value'
# Session
除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。
**交由客户端保管机制:**在服务端设置了 secret_key 之后,当用户成功登陆后,会生成一个session保存在客户端的浏览器上的cookie中,当下次浏览器携带这个cookie来时,取出session,根据自己的secret_key按位相与最后再序列化成字典即可,也就是说只要我的secret_key 没变响应的就能序列化出对应的字典信息
# 基本使用:
设置:session['username'] = 'xxx' 删除:session.pop('username', None) from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' @app.route('/') def index(): if 'username' in session: return 'Logged in as %s' % escape(session['username']) return 'You are not logged in' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': session['username'] = request.form['username'] return redirect(url_for('index')) return ''' <form action="" method="post"> <p><input type=text name=username> <p><input type=submit value=Login> </form> ''' @app.route('/logout') def logout(): # remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index'))
# 自定义session
pip3 install Flask - Session #安装Flask-Session #文件中run.py------------------------------- from flask import Flask from flask import session from pro_flask.utils.session import MySessionInterface app = Flask(__name__) app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' app.session_interface = MySessionInterface() @app.route('/login.html', methods=['GET', "POST"]) def login(): print(session) session['user1'] = 'alex' session['user2'] = 'alex' del session['user2'] return "内容" if __name__ == '__main__': app.run() #utils文件中的session.py------------------------ import uuid import json from flask.sessions import SessionInterface from flask.sessions import SessionMixin from itsdangerous import Signer, BadSignature, want_bytes class MySession(dict, SessionMixin): def __init__(self, initial=None, sid=None): self.sid = sid self.initial = initial super(MySession, self).__init__(initial or ()) def __setitem__(self, key, value): super(MySession, self).__setitem__(key, value) def __getitem__(self, item): return super(MySession, self).__getitem__(item) def __delitem__(self, key): super(MySession, self).__delitem__(key) class MySessionInterface(SessionInterface): session_class = MySession container = {} def __init__(self): import redis self.redis = redis.Redis() def _generate_sid(self): return str(uuid.uuid4()) def _get_signer(self, app): if not app.secret_key: return None return Signer(app.secret_key, salt='flask-session', key_derivation='hmac') def open_session(self, app, request): """ 程序刚启动时执行,需要返回一个session对象 """ sid = request.cookies.get(app.session_cookie_name) if not sid: sid = self._generate_sid() return self.session_class(sid=sid) signer = self._get_signer(app) try: sid_as_bytes = signer.unsign(sid) sid = sid_as_bytes.decode() except BadSignature: sid = self._generate_sid() return self.session_class(sid=sid) # session保存在redis中 # val = self.redis.get(sid) # session保存在内存中 val = self.container.get(sid) if val is not None: try: data = json.loads(val) return self.session_class(data, sid=sid) except: return self.session_class(sid=sid) return self.session_class(sid=sid) def save_session(self, app, session, response): """ 程序结束前执行,可以保存session中所有的值 如: 保存到resit 写入到用户cookie """ domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) val = json.dumps(dict(session)) # session保存在redis中 # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime) # session保存在内存中 self.container.setdefault(session.sid, val) session_id = self._get_signer(app).sign(want_bytes(session.sid)) response.set_cookie(app.session_cookie_name, session_id, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
# 第三方session
""" pip3 install redis pip3 install flask-session """ from flask import Flask, session, redirect from flask.ext.session import Session app = Flask(__name__) app.debug = True app.secret_key = 'asdfasdfasd' app.config['SESSION_TYPE'] = 'redis' from redis import Redis app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379') Session(app) @app.route('/login') def login(): session['username'] = 'alex' return redirect('/index') @app.route('/index') def index(): name = session['username'] return name if __name__ == '__main__': app.run()
← 路由和配置 蓝图、请求扩展和中间件 →