flask之二
预热
- 在渲染模板的时候,默认会从项目根路径下的
templates
目录下查找模板 - 如果想要指定模板路径的时候,就在初始化APP的时候,这样操作即可:
app = Flask(__name__,template_folder='C:/templates') #template_folder可以指定模板位置
模板传参
- 在使用
render_template
渲染模板的时候,可以传递关键字参数,以后直接在模板中使用就可以了 - 如果参数过多的话,那么就可以将所有的参数放到一个字典中,然后再传这个参数的时候使用
**
将字典打散成关键字参数。小例子:
- my_template.py
from flask import Flask,render_template app = Flask(__name__) app.debug = True @app.route('/') def hello_world(): context = { 'username': 'wanghui', 'age':19, 'children':{ 'user':'ccc', 'type':'stu', } } return render_template('index.html', **context) # return render_template('index.html',context=context) # return render_template('index.html',username='wanghui',age=19) if __name__ == '__main__': app.run()
- templates/index.html
my blog 这是模板渲染的数据
{#{{ username }}
#} {#{{ age }}
#} {{ context.username }} {{ context.age }}{{ username }}
{{ children.user }}
模板中的url_for
模板中的
url_for
和视图函数中的url_for
是类似的,也是传递视图函数的名字,也可以传递参数。使用的时候,需要在url_for
两边加上一个{{ url_for('func_name'),ref='/',id='1'}}
- templates.py
from flask import Flask,render_template,url_for app = Flask(__name__) app.debug = True @app.route('/') def hello_world(): return render_template('index.html') @app.route('/accounts/login/
/') def login(id): return render_template('login.html') if __name__ == '__main__': app.run(port=8888) - templates/index.html
my blog 这是从模板中渲染的
- templates/login.html
Login page 这是登录页面
{#{{ 用来存放变量 }}#} {#{% 用来执行函数或者逻辑代码 %}#}过滤器
有时候我们需要在模板中对一些变量进行处理,那么就必须要类似于python中的函数一样,可以将这个值传到函数中,然后做一些操作。在模板中过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器会根据自己的功能,再返回相应的值,之后再将结果渲染到页面上。
- 基本语法:
{{ variable |过滤器的名字 }}
guo - abs(value):返回一个数值的绝对值。 例如:-1|abs。
- default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。name|default('xiaotuo')——如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。
- escape(value)或e:转义字符,会将<、>等符号转义成HTML中的符号。例如:content|escape或content|e。
- first(value):返回一个序列的第一个元素。names|first。
- format(value,*arags,**kwargs):格式化字符串。例如以下代码:
{{ "%s" - "%s"|format('Hello?',"Foo!") }}\ 将输出:Helloo? - Foo!
- last(value):返回一个序列的最后一个元素。示例:names|last。
- length(value):返回一个序列或者字典的长度。示例:names|length。
- join(value,d=u''):将一个序列用d这个参数的值拼接成字符串。
- safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例:
content_html|safe。 int(value):将值转换为int类型。 float(value):将值转换为float类型。 lower(value):将字符串转换为小写。 upper(value):将字符串转换为小写。 replace(value,old,new): 替换将old替换为new的字符串。 truncate(value,length=255,killwords=False):截取length长度的字符串。 striptags(value):删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。 trim:截取字符串前面和后面的空白字符。 string(value):将变量转换成字符串。 wordcount(s):计算一个长字符串中单词的个数。
- default过滤器详解:
如果某个变量使用方式是{{ value|default('默认值')}}
,如果value这个key
不存在的话就使用过滤器提供的默认值;如果类似于python
中判断一个值是否为False(例如:空字典,空字符串,空列表的话)那么久必须要传递另外一个参数{{ value | default('默认值',boolean=True)}}
;
可以使用or
来替换default('默认值',boolean=True)
(例如{{ siginature or '此人很懒没有留下任何说明'}})
例子: - defaulte_falter.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def index(): context = { 'position':-9, 'signature':'', #'signature':'this ismy blog' } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True)
- templates/index.html
MyBlog {#个性签名:{{ signature|default('此人很懒没有留下任何说明!',boolean=True) }}
#}个性签名:{{ signature or '此人很懒没有留下任何说明!'}}
- esacape:转义过滤器
safe
过滤器:可以关闭一公分字符串的自动转义escape
过滤器:对某个字符串进行转义autoescape
过滤器:可以对其代码框内的代码块关闭自动转义- first:返回序列中的第一个元素
- last:返回序列中的最后一个元素
- format:格式化输出
- length:长度计算
- int:转换成整数
- replase:旧字符串换成新的
truncate
:指定长度截取(结合striptags去除掉html字段之后截取纯净字符串然后按字数去做预览页填充)striptags
:去除标签中的html字段- worldcount(s):统计一个长字符串中的单词数
小例子: - escape.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def hello_world(): context = { 'position':-9, 'signature':'', 'persons':['abc','def'], 'age':"18", 'article':'hello hello xxooo xxooo!!' } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True,port=8080)
- templates/index.html
MyBlog {#{% autoescape off %}#} {#个性签名:{{ signature }}
#} {#{% endautoescape %}#}{{ signature|safe }}
{{ persons|first }}
{{ persons[0] }}
{{ persons|last }}
{{ persons[-1] }}
{{ "我的名字是%s"|format("hello word!") }}
{{ "人数是 %d"|format(persons|length) }}
{% if age|int == 18 %}年龄是18岁
{% else %}年龄不是18岁
{% endif %}{{ article|replace('hello','sssssz') }}
{{ article|truncate(length=5) }}
{{ signature|striptags }}
自定义模板过滤器
- 在python文件中写好自己的过滤器(本质上就是一个函数)
- 如果要在模板中调用这个过滤器,那就需要在这个函数上加一个装饰器
@app.template_filter('过滤器名称')
- 自动加载的话就在app下添加
app.config['TEMPLATES_AUTO_RELOAD'] = True
- 小例子:
- define_filter.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True @app.route('/') def hello_world(): context={ 'article':'anyway hello anyway hello abccc' } return render_template('index.html',**context) @app.template_filter('cut') def cut(value): vaule = value.replace("hello","sbsb") return value if __name__ == '__main__': app.run(debug=True,port=9090)**
- templates/index.html
myblog {{ article|cut }}
实战自定义过滤器
- 时间处理(从现在到发帖的时间差)
- shizhan.py
from flask import Flask,render_template from datetime import datetime app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True @app.route('/') def index(): context={ 'article':'aaa bbb ccc', 'create_time':datetime(2018,02,23,10,12,11) } return render_template('index.html',**context) @app.template_filter('handle_time') def handle_time(time): ''' 1.距离现在的时间多久,如果间隔在一分钟以内就表示刚刚 2.在一小时以内就显示xx分钟前 3.在24小时以内就显示xx小时前 4. 在一个月之内就显示多少天之前 5. 否则就显示具体的时间 :param time: :return: ''' if isinstance(time,datetime): now = datetime.now() timestamp = (now - time).total_seconds() #获取间隔秒数 if timestamp < 60: return "刚刚" elif timestamp >=60 and timestamp<= 60*60: minutes = timestamp/60 return "%s分钟前",int(minutes) elif timestamp >= 60*60 and timestamp <= 60*60*24: hours = timestamp/(60*60) return "%s小时前",int(hours) elif timestamp >= 60*60*24 and timestamp<= 60*60*24*30: days = timestamp/(60*60*24) return "%s天前",int(days) else: return time.strftime('%Y-%m-%d %H:%M') if __name__ == '__main__': app.run(port=9092,debug=True)
- templates/index.html
MyBlog 发表时间:{{ create_time|handle_time }}
条件判断
For循环
在
jinjia2
中的for
循环,跟python中的for循环基本是一致的,也是用for in形式;
而且可以便利所有的序列以及迭代器,但是唯一不同的是jinjia2
中的for
循环没有break
和continue
- 小例子:
- for_ex.py
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def hello_world(): context = { 'users':['user01','user02','user03'], 'person':{ 'username':'wanghui', 'age':21, 'country':'china', }, 'books':[ { 'name':'sk1', 'author':'saa', 'price':100, }, { 'name': 'aaaeede1', 'author': 'se232aa', 'price': 103, }, { 'name': 'AAAew', 'author': 'VVVeqwea', 'price': 190, }, { 'name': 'skfdfds1', 'author': 'sdfsfsdfdaa', 'price': 30, } ] } return render_template('index.html',**context) if __name__ == '__main__': app.run(debug=True)
- templates/index.html
MyBlog -
{% for user in users %}
{{ user }}
{% endfor %}用户名 年龄 国家 {% for key,value in person.items() %} {{ value }} {% endfor %}ID 书名 作者 价格 总数 {% elif loop.last %} {% else %} {% endif %} {% endfor %}{{ loop.index }} {{ book.name }} {{ book.author }} {{ book.price }} {{ loop.length }} {% for x in range(1,10) %}
{% for y in range(1,x+1) if y <= x %} {% endfor %}{{ y }}*{{ x }}={{ x*y }} {% endfor %}宏
模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值
使用宏的时候,参数可以是默认值 - 小例子:
- macro.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DEBUG'] = True @app.route('/') def hello_world(): return render_template('index.html') if __name__ == '__main__': app.run(port=9999)
- templates/index.html
Macro {% macro input(name="",value="",type="text") %} {% endmacro %}登陆页面
用户名: {{ input('username') }} 密码: {{ input('password',type='password') }} {{ input(value='提交',type='submit') }} 宏的导入
在真实的开发中,会将一些常用的宏单独放在一个文件中,在需要使用的时候,再从这个文件中进行导入。
import语句的用法跟python中的import类似,可以直接import...as...,也可以from...import...或者from...import...as...,假设现在有一个文件,叫做forms.html,里面有两个宏分别为input和textarea,如下:
注意事项:
a. inport
宏文件 as xxx
b. from 宏文件路径 import 宏的名字 [as xxx]
c. 宏文件的路径,不要以相对路径去找,都要以templates
作为绝对路径去找
d. 如果想要在导入宏的时候,就把当前末班的一些参数传递给宏所在的模板,那么就应该在导入的时候使用with context
- 小例子:
- macros.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DEBUG'] = True @app.route('/') def hello_world(): return render_template('index/index.html') if __name__ == '__main__': app.run(port=9999)
- templates/macros/macros.html
{% macro input(name="",value="",type="text") %} {% endmacro %}
- templates/index/index.html
{#{% from "macros.html" import input as inp %}#} {% import "macros/macros.html" as macros with context %}
Macro 登陆页面
用户名: {{ macros.input('username') }} 密码: {{ macros.input('password',type='password') }} {{ macros.input(value='提交',type='submit') }} include标签
- 这个标签相当于是将指定模板中的代码复制粘贴到当前的位置
include
标签,如果要继续使用父模板中的变量,直接用就可以了include
的路径也和import一样,需要从templates为根,不要以相对路径去找。
- 小例子:
- include_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config['TEMPLATES_AUTO_RELOAD'] @app.route('/') def hello_world(): return render_template('index.html',username='wanghui') @app.route('/detail/') def detail(): return render_template('course_detail.html') if __name__ == '__main__': app.run(debug=True)
- templates/index.html
MyBlog {% include "common/header.html" %}中间的{% include "common/footer.html" %}- {{ username }}
- templates/course_detail.html
Title {% include "common/header.html" %}文章详情!{% include "common/footer.html" %} - templates/common/header.html
- templates/common/footer.html
set with语句
- 在模板中,可以使用
set
来定义变量;一旦定义了这个变量。那么在后面的代码中,都可以使用这个变量。 with
语句定义的变量,只能在with
的代码块中使用。超出with
代码块,则不能使用with
不一定要跟一个变量,也可以是一个空的with
语句,以后要用的话,就在with
中使用set
定义的变量来使用。
{% set username='wanghui' %}
用户名:{{ username }}
{% with %}
{% set cla***oom='2018' %}
班级:{{ cla***oom }}
{% endwith %}
别的班级{{ cla***oom }}
加载静态文件
- 加载静态文件使用的是
url_for
函数,第一个参数为static
,第二个参数是filename='path'
- 路径查找要以
static
目录作为根目录 - 小例子:
- static_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True, }) @app.route('/') def hello_world(): return render_template('index.html') if __name__ == '__main__': app.run()
- static_ex.py
- static/css/index.css
body{ background: pink; }
- static/js/index.js
alert('hello user!')
- static/imgs/sas.jpg
图片
- templates/index.html
Title 模板继承
为什么需要模板继承?
- 可以将一些公用的代码单独抽取出来放到一个父模板中,以后子模板直接继承就给可以使用了。
- 这样可以减少重复性的代码,并且以后代码修改起来也很方便
模板继承的语法
- 使用
extends
语句来指明继承的父模板。父模板的路径也就是相对于templates
文件夹下的绝对路径。例子如下{% extends 'base.html' %}
block语法
一般在父模板中只能定义一些共性公用的代码,子模板可能要根据不同的需求实现不同的代码。这时候父模板就应该提供一个接口,让子模板来实现。从而实现业务的具体功能。
- 在父模板中
{% block body_block %}
我是base下的
{% endblock %} - 在子模板中
{% block body_block %}
我是index的内容
{% endblock %}调用父模板代码block中的代码
默认情况下,字幕版实现了父模板定义的block,那么子模板中block的代码就会覆盖掉父模板中的代码,要想保留父模板中的block的话就是用
{{ super() }}
来实现 - 父模板的内容:
{% block body_block %}
base.html
{% endblock %} - 子模板中的内容:
{% extends 'base.html' %} {% block body_block %} {{ super() }}
我是index的内容
{% endblock %}调用另外一个block中的代码
在另外一个模板中使用其他模板中的代码,可以使用
{{ self.blockname() }}
即可 - 父模板
{% block title %} {% endblock %} {% block body_block %}base.html
{% endblock %} - 子模板:
{% extends 'base.html' %} {% block title %} MyIndex {% endblock %} {% block body_block %} {{ super() }} {{ self.title() }}
我是index的内容
{% endblock %}其他注意事项
- 继承的代码必须放在子模板中的第一行
{% extends 'base.html' %}
- 子模板中要实现自己的代码,要放到block中,不然不生效
继承的例子:
- inherit_ex.py
from flask import Flask,render_template app = Flask(__name__) app.config.update({ 'DEBUG':True, 'TEMPLATES_AUTO_RELOAD':True }) @app.route('/') def index(): return render_template('index.html') @app.route('/detail/') def detail(): return render_template('course_detail.html') if __name__ == '__main__': app.run()
- templates/base.html
{% block title %} {% endblock %} {% block body_block %}base.html
{% endblock %} - templates/index.html
{% extends 'base.html' %} {% block title %} MyIndex {% endblock %} {% block body_block %} {{ super() }} {{ self.title() }}
我是index的内容
{% endblock %} - templates/course_detail.html
{% extends 'base.html' %} {% block body_block %}
this is course
{% endblock %}