1.模板语言jinja2

  Flask中默认的模板语言是Jinja2

1.0 模板传参

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
content = {
"name":"learning",
"age":"",
"sex":"男"
}
return render_template("index.html",**content) if __name__ == "__main__":
app.run(port=5225,debug=True)

index.html

<div>
{{ name }}
{{ age }}
{{ sex }}
</div>

效果

1.1 从后端传HTML标签

# 常规做法,前端引入safe

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ tags|safe }}
</body>
</html>

app.py

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
tags = "<input type='text' name='user' value='输入'>"
return render_template("login.html",tags=tags) if __name__ == "__main__":
app.run(port=5225,debug=True)

# 引入Markup,它的作用在HTML的标签上做一层封装,让Jinja2模板语言知道这是一个安全的HTML标签

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ tags }}
</body>
</html>

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)

@app.route("/")
def index():
tags = "<input type='text' name='user' value='输入'>"
markup = Markup(tags)
return render_template("login.html",tags=markup) if __name__ == "__main__":
app.run(port=5225,debug=True)

1.2 模板内执行函数

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)

# 定义一个函数
def sums(a,b):
return a+b @app.route("/")
def index():
return render_template("login.html",tags=sums) if __name__ == "__main__":
app.run(port=5225,debug=True)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ tags }}
<div>{{ tags(38,37) }}</div>
</body>
</html>

效果:

1.3 flask中的装饰器

from flask import Flask,request,redirect,render_template,session
app = Flask(__name__)
app.secret_key = "" # 开启session功能的时候必须添加该配置secret_key
# 模拟数据
STUDENT_DICT = {
1: {'name': '吕洋'},
2: {'name': '黄晓'},
3: {'name': '余烬'},
} @app.route("/login",methods=["GET","POST"])
def login():
if request.method =="GET":
return render_template("login.html") if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
if username =="bob" and password == "":
session["user"] = username
return redirect("/index")
else:
return render_template("login.html", msg="用户名密码错误") @app.route("/index")
def index():
if session.get("user"):
return render_template("index.html",stu=STUDENT_DICT)
return redirect("/login") if __name__ == "__main__":
app.run(port=5225,debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1px">
<tr>
<th>id</th>
<th>name</th>
<th>option</th>
</tr>
<tr>
{% for k,v in stu.items() %}
<td>{{ k }}</td>
<td>{{ v.name }}</td>
<td><a href="/detail?id={{ k }}">详细</a>|<a href="/delete/{{ k }}">删除</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>

# 用户必须先登录,才能访问index

效果:

说明:

  html模板渲染一般都存放在项目主目录下的templates下,否则会出现一个jinja2的异常

  开启session功能,这里必须要添加secret_key,如果在实例化的app中没有 secret_key 会抛异常

1.4 特殊装饰器

函数类:

@app.template_global()和@app.template_filter()

  和django中的inclusion_tag以及filter很类似   

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ sums(15,15) }}
{{ 22|a_b_c_sum(15,15) }} </body>
</html>

在模板中执行函数,需要先定义一个函数:

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)

@app.template_global()
def sums(a,b):
return a+b @app.template_filter()
def a_b_c_sum(a, b, c):
return a + b + c @app.route("/")
def index():
return render_template("login.html",tags="") # 注意这里也不一样了 if __name__ == "__main__":
app.run(port=5225,debug=True)

非函数类:

before_request 和 after_request

  @before_request注册一个函数,在每次请求之前执行,返回None则运行通过

  @before_first_request,注册一个函数,在处理第一个请求之前执行。它和@before_request一样,唯一区别是它只执行一次

  @after_request 注册一个函数,会在用户请求得到response响应之后,还未返回用户之前执行,它可以做统计访问量来使用

  @teardown——request 注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行

from flask import Flask,request,redirect,session

app = Flask(__name__)
app.secret_key = "fsdfs" @app.before_request
def is_login(): # 判断是否登录
# 白名单设置,判断为登录页面时
if request.path == "/login":
# 跳过处理
return None
# 判断session是不存在时
if not session.get("user"):
# 重定向到登录页面
return redirect("/login") @app.route("/login")
def login():
pass if __name__ == '__main__':
app.run("0.0.0.0", 5000)

1.5 模板复用block

  和django中的模板使用方式一样

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <h1>Welcome to My</h1>
<h2>下面的内容是不一样的</h2>
{% block content %} {% endblock %}
</body>
</html>

login.html

{% extends "index.html" %}
{% block content %}
<h4>欢迎登陆</h4>
<form>
用户名:<input type="text" name="user">
密码:<input type="text" name="pwd">
<input type="submit" value="提交">
</form>
{% endblock %}

1.6 模板引用include

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <h1>Welcome to My</h1> {% include "login.html" %}
</body>
</html>

login.html

<form>
用户名:<input type="text" name="user">
密码:<input type="text" name="pwd">
<input type="submit" value="提交">
</form>

1.7 模板中的过滤器

常用的过滤器

abs    # 绝对值
default  # 如果当前变量没有值,则会使用参数中的值来替代
escape  # 转义字符
first    #返回一个序列的第一个元素
format    #格式化字符串
last    # 返回一个序列的最后一个元素
length    # 返回一个序列的长度
join    # 拼接字符串
safe    # 关掉转义
int    # 转为int类型
float    # 转为浮点类型
lower    # 转换为小写
upper    # 转换为大写
replace    # 替换
truncate  # 截取length长度的字符串
striptags  # 删除字符串中所有的html标签,如果出现多个空格,将替换成一个空格

default过滤器的使用

  他比较特别,使用必须要加上boolean=True

@app.route("/")
def index():
content = {
"direction":None
}
return render_template("index.html",**content)

index.html

<div>
{{ direction|default("这是对default的使用说明",boolean=True) }}
</div>

效果

2. 路由相关(装饰器中的参数)

2.1 实例

from flask import Flask,request

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"])
def student_info():
stu_id = int(request.args["id"]) # 获取前端url中的id值,注意格式类型
return f"如家{stu_id}号房" # Python3.6的新特性 f"{变量名}" if __name__ == "__main__":
app.run(port=5225,debug=True)

效果:

2.3 endpoint

  反向url地址,默认为视图函数名 (url_for)

from flask import Flask,request,url_for

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"],endpoint="r_info")
def student_info():
print(url_for("r_info"))    # /info
stu_id = int(request.args["id"]) # 获取前端url中的id值,注意是格式类型
return f"如家{stu_id}号房" # Python3.6的新特性 f"{变量名}" if __name__ == "__main__":
app.run(port=5225,debug=True)

url栏输入http://127.0.0.1:5225/info?id=2,会打印出如上代码

2.3 url_for

  用于反向生成url,也可以附带一些参数,比如想要完整的URL,可以设置_external为Ture

from flask import Flask,request,url_for

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"],endpoint="r_info")
def student_info():
print(url_for("r_info", _external=True)) # http://127.0.0.1:5225/info
stu_id = int(request.args["id"]) # 获取前端url中的id值,注意是格式类型
return f"如家{stu_id}号房" # Python3.6的新特性 f"{变量名}" if __name__ == "__main__":
app.run(port=5225,debug=True)

# 这样我们获取了完整路径,但是参数还未获取,可以在后面再追加上我们的id, url_for("r_info", _external=True,id=stu_id),这样就能获取完整url

   对于url_for,我们还可以通过视图函数解析出url

from flask import Flask,request,url_for
app = Flask(__name__) @app.route('/')
def hello_world():
return url_for('my_list',page=6) #url_for里面:第一个是视图函数,第二个是url需要的参数 @app.route('/list/<page>/')
def my_list(page):
return 'my_list' if __name__ == "__main__":
app.run(port=5225,debug=True)

效果

  url_for里面多余的参数会当做搜索字符

@app.route('/')
def hello_world():
return url_for('my_list',page=2,count=2,age=18) @app.route('/list/<page>/')
def my_list(page):
return 'my_list'

效果

2.4 defaults

  视图函数的参数默认值{"nid":100}

2.5 strict_slashes

   url地址结尾符"/"的控制

   False : 无论结尾 "/" 是否存在均可以访问

  True : 表示开启路由严格匹配模式,结尾必须不能是 "/"

from flask import Flask

app = Flask(__name__)

@app.route("/info",strict_slashes=True)
def student_info():
return "如家" if __name__ == "__main__":
app.run(port=5225,debug=True)

# 为True,路由末尾不能再加反斜杠,不然报错

# 为False,路由末尾对反斜杠不做严格要求

2.6 redirect_to

  url地址重定向

from flask import Flask
app = Flask(__name__) @app.route("/info",redirect_to="/bbb")
def student_info():
return "如家" @app.route("/bbb")
def bbb():
return "去你的"

# 输入http://127.0.0.1:5225/info,它会自动发生跳转,到http://127.0.0.1:5225/bbb

3. 动态参数路由

from flask import Flask,url_for
app = Flask(__name__) @app.route("/info/<int:nid>",endpoint="r_info")
def student_info(nid):
print(url_for("r_info", _external=True, nid=nid))
return f"如家{nid}" if __name__ == "__main__":
app.run(port=5230,debug=True)

效果:

3.1常见 @app.route() 装饰器中的动态参数

@app.route('/user/<username>')   # 不加参数的时候默认是字符串形式的
@app.route('/post/<int:post_id>') # 指定int,说明是整型的
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')
@app.route('/login', methods=['GET', 'POST'])

对应关系

DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,  接收多个路径
'path': PathConverter,  和string类似,但是接收斜杠
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}

 对于any:

@app.route("/<any(blog,user):url_path>/<id>/")
def index(url_path,id):
if url_path == 'blog':
return '博客详情%s' % id
else:
return '用户详情%s' % id

效果

对于path

@app.route('/article/<path:test>/')
def test_article(test):
return 'test_article:{}'.format(test)

效果:

3.2 路由正则

具体代码演示

from flask import Flask
from werkzeug.routing import BaseConverter # 自定义正则转换器
class RegexConverter(BaseConverter):
def __init__(self, url_map, *args):
super(RegexConverter, self).__init__(url_map)
# 将接受的第1个参数当作匹配规则进行保存
self.regex = args[0] app = Flask(__name__) # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re
app.url_map.converters['re'] = RegexConverter @app.route('/user/<re("[0-9]{3}"):user_id>')
def user_info(user_id):
return "user_id 为 %s" % user_id if __name__ == "__main__":
app.run(debug=True)

效果

也可以参考祥哥博客

4.实例化Flask参数

4.1 flask配置

开启debug模式

from flask import Flask

app = Flask(__name__)  # type:Flask
app.config["DEBUG"] = True if __name__ == '__main__':
app.run()

config中的所有key值

{
'DEBUG': False, # 是否开启Debug模式
'TESTING': False, # 是否开启测试模式
'PROPAGATE_EXCEPTIONS': None, # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True
'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一两句话说不清楚,一般不用它
'SECRET_KEY': None, # 之前遇到过,在启用Session的时候,一定要有它
'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命周期(天)默认31天
'USE_X_SENDFILE': False, # 是否弃用 x_sendfile
'LOGGER_NAME': None, # 日志记录器的名称
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None, # 服务访问域名
'APPLICATION_ROOT': None, # 项目的完整路径
'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字
'SESSION_COOKIE_DOMAIN': None, # 在哪个域名下会产生session记录在cookies中
'SESSION_COOKIE_PATH': None, # cookies的路径
'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否应被设置 httponly 的标志,
'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否应被设置安全标志
'SESSION_REFRESH_EACH_REQUEST': True, # 这个标志控制永久会话如何刷新
'MAX_CONTENT_LENGTH': None, # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码
'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默认缓存控制的最大期限
'TRAP_BAD_REQUEST_ERRORS': False,
# 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样,
# 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。
'TRAP_HTTP_EXCEPTIONS': False,
# Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。
# 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。
# 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。
# 如果这个值被设置为 True ,你只会得到常规的回溯。
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http', # 生成URL的时候如果没有可用的 URL 模式话将使用这个值
'JSON_AS_ASCII': True,
# 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False ,
# Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。
# 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。
'JSON_SORT_KEYS': True,
#默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。
# 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。
# 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
}

4.2 对于配置的修改

  我们可以创建一个setting文件

class FlaskSetting(object):
DEBUG = True

  需要使用,直接导入就可以

4.3 实例化配置

static_folder = 'static',  # 静态文件目录的路径 默认当前项目中的static目录
static_host = None, # 远程静态文件所用的Host地址,默认为空
static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用
# host_matching是否开启host主机位匹配,是要与static_host一起使用,如果配置了static_host, 则必须赋值为True
# 这里要说明一下,@app.route("/",host="localhost:5000") 就必须要这样写
# host="localhost:5000" 如果主机头不是 localhost:5000 则无法通过当前的路由
host_matching = False, # 如果不是特别需要的话,慎用,否则所有的route 都需要host=""的参数
subdomain_matching = False, # 理论上来说是用来限制SERVER_NAME子域名的,但是目前还没有感觉出来区别在哪里
template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录
instance_path = None, # 指向另一个Flask实例的路径
instance_relative_config = False # 是否加载另一个实例的配置
root_path = None # 主模块所在的目录的绝对路径,默认项目目录

4.4 template_folder

  如果设置template_folder = 'templates',这里面的templates它是相对路径!

  我们在使用该模板时,应该这么设置  template_folder = '../templates'

结构图:

./
├── bin
│ └── app.py
├── static
│ └── learning.jpg
└── templates
└── login.html

案例:

from flask import Flask,render_template
from flask_login import login_required # 第三方包,需要下载
app = Flask(__name__,template_folder="../templates") # 有时候会找不到,需加上template_folder @app.route("/")
def login():
return render_template("login.html") @app.route("/log")
@login_required # 不能直接访问该路由
def index():
return render_template("index.html") if __name__ == "__main__":
app.run(port=5230,debug=True)

4.5 static_folder

  静态文件目录的路径 默认当前项目中的static目录

结构图

./
├── bin
│ └── app.py
├── static
│ └── learning.jpg
└── templates
└── login.html

app.py

from flask import Flask,render_template

app = Flask(__name__,template_folder="../templates",static_folder="../static")

@app.route("/")
def index():
return render_template("login.html") if __name__ == "__main__":
app.run(port=5230,debug=True)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>头像</h3>
<img src="/static/learning.jpg" alt="">
</body>
</html>

效果

4.6 static_url_path

from flask import Flask,render_template

app = Flask(__name__,template_folder="../templates",static_folder="../static",static_url_path="/app")

@app.route("/")
def index():
print(app.static_folder) # C:\Users\Learning\Desktop\ffflask\bin\../static
print(app.static_url_path) # /app
return render_template("login.html") if __name__ == "__main__":
app.run(port=5230,debug=True)

5. 内置session

  上面案例已经使用过session,这里只强调一点,使用session必须配制secret_key,它是一段秘钥字符串,自己随意填写

from flask import session
app = Flask(__name__)
app.secret_key = "ask"

一般session我们可以做登录验证使用

flask模板语言,装饰器,路由及配置的更多相关文章

  1. flask session,蓝图,装饰器,路由和对象配置

    1.Flask 中的路由   *endpoint - url_for 反向地址  *endpoint 默认是视图函数名  *methods 指定视图函数的请求方式,默认GET  defaults={& ...

  2. 【Flask】 python学习第一章 - 4.0 钩子函数和装饰器路由实现 session-cookie 请求上下文

    钩子函数和装饰器路由实现 before_request 每次请求都会触发 before_first_requrest  第一次请求前触发 after_request  请求后触发 并返回参数 tear ...

  3. Flask - 模板语言jinja2 和render_template高级用法

    目录 Flask - 模板语言jinja2 和render_template高级用法 一. 字典传递至前端 二. 列表传入前端Jinja2 模板的操作: 三. 大字典传入前端 Jinja2 模板 四. ...

  4. Flask 模板语言,装饰器

      Jinja2模板语言 # -*- coding: utf-8 -*-   from flask import Flask, render_template, request, redirect,  ...

  5. flask模板语言

    由于Django的模板引擎和Flask中的Jinja2模板引擎有很多一样的地方,所以我将一样的地方总结到了独立的文章中 https://www.cnblogs.com/kuxingseng95/art ...

  6. flask模板语言 jinja2 以及render_template 深度用法

    是时候开始写个前端了,Flask中默认的模板语言是Jinja2 现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下 首先我们要在后端定义几个字符 ...

  7. python flask route中装饰器的使用

    问题:route中的装饰器为什么感觉和平时使用的不太一样,装饰器带参数和不太参数有什么区别?被修饰的函数带参数和不带参数有什么区别? 测试1:装饰器不带参数,被修饰的函数也不带参数. def log( ...

  8. flask --- 03 .特殊装饰器, CBV , redis ,三方组件

    一.特殊装饰器(中间件) 1.before_request 在请求进入视图函数之前 @app.before_request def look(): 2. after_request 在结束视图函数之后 ...

  9. Flask系列06--(中间件)Flask的特殊装饰器 before_request,after_request, errorhandler

    一.使用 Flask中的特殊装饰器(中间件)方法常用的有三个 @app.before_request # 在请求进入视图函数之前 @app.after_request # 在请求结束视图函数之后 响应 ...

随机推荐

  1. flask路由末端带斜线和不带斜线的区别

    路由末端带有“/” app.route('/test/') 在浏览器中输入http://127.0.0.1:5000/test/ 和http://127.0.0.1:5000/test都能访问 路由末 ...

  2. maven仓库中的LastUpdated文件删除脚本

    cleanLastUpdated.bat(windows版本) @echo off rem create by NettQun rem 这里写你的仓库路径 set REPOSITORY_PATH=D: ...

  3. react相关知识点链接整理

    1.React组件之间的通信 2.中间件做代理解决跨域问题 3.不要再问我跨域的问题了 4.React 组件数据流 && 组件间沟通 5.如何理解虚拟DOM 6.react性能调谐与d ...

  4. js-JavaScript的简介

    JavaScript的简介 * 是基于对象和事件驱动的语言,应用于客户端 - 基于对象: ** 提供好了很多对象,可以直接拿过来使用 - 事件驱动: ** HTML做网站静态效果,JavaScript ...

  5. JavaScript的进阶之路(三)引用类型之Object类型和Array类型

    引用类型 Object类型 function a(num){ if(num>3){ a(--num); } console.log(num); } a(5); //如何创建对象的实例 var o ...

  6. 文字编辑器FCKeditor 简介以及基本配置和使用方法

    什么是FCKeditor FCKeditor是一个专门使用在网页上属于开放源代码的所见即所得文字编辑器.它志于轻量化,不需要太复杂的安装步骤即可使用.它可和PHP.JavaScript.ASP.ASP ...

  7. 139.00.003 Git学习-Git时光机之Inbox体系(三)

    一.Git时光机之Inbox 体系 工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库. Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有G ...

  8. SQL Server ->> SQL Server 2016新特性之 -- sp_set_session_context存储过程和SESSION_CONTEXT函数

    sp_set_session_context存储过程和SESSION_CONTEXT函数出现在了SQL Server 2016 CTP3.0上.它俩配合起来的作用是sp_set_session_con ...

  9. C++程序运行时间-ZZ

    [15.5.25]贴一段实用的代码,linux下跑过. #include <stdio.h> /* printf */ #include <time.h> /* clock_t ...

  10. C++ Deque(双向队列)

      C++ Deque(双向队列)是一种优化了的.对序列两端元素进行添加和删除操作的基本序列容器.它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的 ...