函数返回一段前端代码,会被flask自动解析,在前端中展示。
@app.route('/index')
def index():
return '请输入:
'
但直接返回html代码,不利于前后端分离,flask为此提供了Jinja2模板引擎,可以通过render_template()方法渲染模板,再返回给前端。
写一个简单的html文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h6>请输入:h6>
<input name="inp">
body>
html>
用render_template()渲染,flask会在templates文件夹内找到要渲染的html文件。
from flask import render_template
@app.route('/')
def hello_world():
return render_template('index.html')
在前端开发过程中,也需要css、js 静态文件,flask提供了一个static的文件夹,用于存储相关静态文件。
在static问价夹下新建一个css文件夹用于存储css文件,同理也可在此新建一个js文件夹,用于存储js文件。
这里可以用到url_for()来获取文件地址
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
<link rel="stylesheet" href="{
{ url_for('static',filename='css/index.css') }}">
head>
<body>
<h6>请输入:h6>
<input name="inp">
body>
html>
css修改h6标签颜色
h6{
color: aquamarine;
}
如果想修改静态文件默认位置,可以在flask初始化时候设置static_folder
from flask import Flask
app = Flask(__name__,static_folder='staticfiles')
如果想要自定义模板存放位置,可以在初始化flask的时候,设置template_folder
from flask import Flask
app = Flask(__name__,template_folder='./static/templates')
render_template(template_name_or_list,**context) 中第一个参数为要渲染的模板或带有模板名称的迭代器,但指挥渲染第一个,第二个参数即为要传给前端的参数。
@app.route('/')
def hello_world():
return render_template('index.html',username='Tom',password='123456')
对于username等,前端可以通过{ { username }}的形式直接使用。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h1>{
{ username }}h1>
<h2>{
{ password }}h2>
body>
html>
@app.route('/')
def hello_world():
dic = {
'username':'Tony',
'password':'123456z'
}
return render_template('index.html',dic = dic)
将所有要穿的参数封装成一个字典传dic给前端,前端可以通过{ {dic.username}}或{ {dic[‘username’]}}的形式取到
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h1>{
{ dic.username }}h1>
<h2>{
{ dic['password'] }}h2>
body>
html>
首先将所有变量封装成字典,然后通过**传递。
@app.route('/')
def hello_world():
context = {
'username':'Tony',
'password':'123456z',
'score':{
'Chinese':89,
'math':96,
'PE':70
}
}
return render_template('index.html',**context)
与封装成字典传参不同的是,**context传参前端可以直接通过所需参数名获取
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h1>{
{ username }}h1>
<h2>{
{ password }}h2>
<h3>{
{ score.Chinese }}h3>
<h3>{
{ score.math }}h3>
<h3>{
{ score['PE'] }}h3>
body>
html>
@app.route('/')
def hello_world():
dic = {
'username':'Tony',
'password':'123456z'
}
li = ['Jack','Tom']
tup =(1,3,5)
return render_template('index.html',li = li,tup=tup,dic = dic)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h1>{
{ li.0 }}h1>
<h1>{
{ li[1] }}h1>
<h2>{
{ tup.0 }}h2>
<h2>{
{ tup[2] }}h2>
<h3>{
{ dic.username }}h3>
<h3>{
{ dic['password'] }}h3>
body>
html>
Flask采用Jinja2模板引擎,Jinja模板语法受Django和Python启发,有Python和Django基础更容易理解。
@app.route('/')
def hello_world():
li = ['Jack','Tom','Kitty']
return render_template('index.html',li = li)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h1>
{% for item in li%}
{# 这里是注释的内容 #}
{
{ item }}
{% endfor %}
h1>
body>
html>
abs绝对值
@app.route('/')
def hello_world():
li = [1,-2,3,-4]
return render_template('index.html',li = li)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h2>
{% for item in li %}
{
{ item|abs }}
{% endfor %}
h2>
body>
html>
@app.route('/')
def hello_world():
li = ['tom','kitty','sindy','jack']
return render_template('index.html',li = li)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h2>
{% for item in li %}
{
{ item|capitalize }}
{% endfor %}
h2>
body>
html>
default
如果传入的变量为空,会打印定义好的文字,如果不为空要打印变量,需要设置boolean=true。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h2>
{
{ is_null|default('this varity is not defined') }}
<br>
{
{ "--"|default('this varity is not defined',boolean=true) }}
h2>
body>
html>
dictsirt字典排序
dictsort可以按键或值对字典进行排序,用关键字by来控制,用reverse=true来控制升序,默认false,降序。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h2>
原数据:
<br>
{
{ mydict }}
<br>
按键排序:
<br>
{% for item in mydict|dictsort(by ='key') %}
{
{ item }}
{% endfor %}
<br>
按值排序 降序:
<br>
{% for item in mydict|dictsort(by ='value') %}
{
{ item }}
{% endfor %}
<br>
按值排序 升序:
<br>
{% for item in mydict|dictsort(by ='value',reverse=true) %}
{
{ item }}
{% endfor %}
<br>
{
{ mydict }}
h2>
body>
html>
escape转义
在字符串中,如果存在&,<,>等,需要转义成普通字符,才能避免被渲染成html元素,然在flask中会自动将这些字符转义成普通字符。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{
{ '<h1>你好!; 北京。h1>' }}
h3>
<h2>
{
{ '<h1>你好!; 北京。h1>'|e }}
h2>
<h1>
{
{ '<h1>你好!; 北京。h1>'|escape }}
h1>
body>
html>
first、last、length
first返回元素第一项目,last返回最后一个元素,length返回元素长度
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{
{ 'hello'|first }}
h3>
<h2>
{
{ 'hello'|last }}
h2>
<h1>
{
{ 'hello'|length }}
h1>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{
{ [1,2,3,4,5]|join }}
h3>
<h2>
{
{ [1,2,3,4,5]|join(',') }}
h2>
<h1>
{
{ [1,2,3,4,5]|join('->') }}
h1>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{
{ 'everyday,everynight'|replace('every','no') }}
h3>
body>
html>
其他过滤器
其他过滤器在此不做详细阐述,可以参考jinja官网上内置过滤器列表查看所有jinja过滤器。
通过装饰器template_filter()可以在后端自定义过滤器。
@app.template_filter('my_replace')
def rep(value):
return value.replace('.','!')
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{
{ 'everyday,everynight.' }}
h3>
<h3>
{
{ 'everyday,everynight.'|my_replace }}
h3>
body>
html>
结构控制包括for循环、if/elif/else条件语句、宏以及块,用{% …%}来控制,每个控制语句要有对应的{% end… %}来结束。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{
{ item }}
{% endfor %}
h3>
body>
html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{% for item in [] %}
{
{ item }}
{% else %}
did not iterate
{% endfor %}
h3>
body>
html>
如上,用{% endfor %} 来结束循环。
for-loop特殊变量访问
loop.index
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 从1开始的迭代 #}
{
{ loop.index }}:{
{ item }}
<br>
{% endfor %}
h3>
body>
html>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 从0开始的迭代 #}
{
{ loop.index0 }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 从item.length到1的迭代 #}
{
{ loop.revindex }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 从item.length-1到0的迭代 #}
{
{ loop.revindex0 }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 是否为第一次迭代,返回布尔值 #}
{
{ loop.first }}:{
{ item }}
<br>
{% endfor %}
h3>
loop.last
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 是否为最后一次迭代,返回布尔值 #}
{
{ loop.last }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 返回元素数目 #}
{
{ loop.length }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 在指定元素中循环产生索引 #}
{
{ loop.cycle('a','b') }}:{
{ item }}
{
{ loop.cycle('a','b','c','d') }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 迭代深度,从1开始 #}
{
{ loop.depth }}:{
{ item }}
<br>
{# 迭代深度,从0开始 #}
{
{ loop.depth0 }}:{
{ item }}
<br>
{% endfor %}
h3>
loop.previtem
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 查看元素的前一个元素 #}
{
{ loop.previtem }}:{
{ item }}
<br>
{% endfor %}
h3>
<h3>
{% for item in ['Tom','Jack','Tony'] %}
{# 查看元素的后一个元素 #}
{
{ loop.nextitem }}:{
{ item }}
<br>
{% endfor %}
h3>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<h3>
{% for item in ['about','boy','kill'] %}
{
{ item }}
{% if item|first =='a' %}
该字母以a开头
{% elif item|first == 'b' %}
该字母以b开头
{% else %}
该字母不以a、b开头
{% endif %}
<br>
{% endfor %}
h3>
body>
html>
可以将宏理解为函数,复用功能,以避免代码重复,可以传参但没有返回值。
用{% macro name(parameter1,parameter2,…) %}的形式来定义宏,parameter为参数,可以设置默认值。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
{% macro input(name,value='',type='text',size=20) %}
{% endmacro %}
<p>用户名:{
{ input('username') }}p>
<p>密 码:{
{ input('password',type='password') }}p>
<p>{
{ input('提交',type='submit') }}p>
body>
html>
import宏
在世纪开发中,会把宏放入一个单独的html文件中,在使用的时候需要导入
macro.html文件
<html lang="en">
<head>
<meta charset="UTF-8">
<title>macrotitle>
head>
<body>
{% macro input(name,value='',type='text',size=20) %}
{% endmacro %}
body>
html>
index.html
import
{% import 'macro.html' as marco %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<p>用户名:{
{ marco.input('username') }}p>
<p>密 码:{
{ marco.input('password',type='password') }}p>
<p>{
{ marco.input('提交',type='submit') }}p>
body>
html>
from … import …
{% from 'macro.html' import input %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<p>用户名:{
{ input('username') }}p>
<p>密 码:{
{ input('password',type='password') }}p>
<p>{
{ input('提交',type='submit') }}p>
body>
html>
块的存在为jinjia模板继承提供了很大的便利,用{% block name %}来定义,每个块结束都由对应的{% endblock %} 来控制,也可用{% endblock name %} 来结束以增加可读性。
*{
margin: 0;
padding: 0;
}
.bg{
width: 1500px;
height: 50px;
background-color: #e7b434;
}
#top{
background-color: antiquewhite;
}
#footer{
background-color: #6d6a6a;
}
父模板
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title%}
base
{% endblock %}
title>
<link rel="stylesheet" href="{
{ url_for('static',filename='css/base.css') }}">
head>
<body>
<div id="top" class="bg">
div>
<div class="bg">
{% block center %}
<h1>这里是要被继承的父模块h1>
{% endblock %}
div>
<div id="footer" class="bg">div>
body>
html>
@app.route('/block/')
def block():
return render_template('base.html')
子模块
{% extends 'base.html' %}
{% block title %}
extend
{% endblock %}
{% block center %}
<h2>这是继承了父模板的子模板h2>
{% endblock %}
@app.route('/extendblock/')
def extendblock():
return render_template('extend.html')
可以看到子模块中只需要修改被block包裹的部分即可。
用super()调用父块结果:
{% extends 'base.html' %}
{% block title %}
extend
{% endblock %}
{% block center %}
<h2>这是继承了父模板的子模板h2>
{
{ super() }}
{% endblock %}
@app.route('/parent/')
def parent():
return render_template('parent.html')
@app.route('/child/')
def child():
return render_template('child.html')
@app.route('/grandchild/')
def grandchild():
return render_template('grandchild.html')
parent
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}
Parent
{% endblock %}
title>
head>
<body>
body: {% block body %}This is from parent.{% endblock %}
body>
html>
child
{% extends 'parent.html' %}
{% block title %}Child
{% endblock%}
{% block body %} This is Child. {
{ super() }}
{% endblock %}
grandchild
{% extends 'child.html' %}
{% block title %} Grandchild{% endblock %}
{% block body %}This is grandchild.
{
{ super.super() }}
{% endblock %}
parent
child
grandchild
用super.super()可以引用parent。
可以理解成定义变量并赋值,有作用域限制,在块内设置的变量无法现实在块外,循环中设置的也无法显示在循环外。如下,在循环内外set一个相同的item,
<html lang="en">
<head>
<meta charset="UTF-8">
<title>settitle>
head>
<body>
{% set item = 0 %}
{% for i in [1,2,3] %}
i = {
{ i }}
{% set item = i %}
item = {
{ item }}
<br>
{% endfor %}
{% if item == 0%} item {% endif %}
body>
html>
如果想实现跨作用域传播,可以通过namespace的方法。
如下,通过namespace() set n.flage = false,n.s=1
<html lang="en">
<head>
<meta charset="UTF-8">
<title>settitle>
head>
<body>
{% set n = namespace(flage=false,s=1) %}
{% for item in [1,2,3,4] %}
{
{ item }}
{% if item > 3%}
{% set n.flage = true %}
{% set n.s = item %}
{% endif %}
<br>
{% endfor %}
n.flage:{
{ n.flage }},n.s:{
{ n.s }}
body>
html>
Jinjia表达式与python非常相似,有python基础的更好理解,这里只稍微列举,详细请见Jinjia官网