在使用PyCharm Professional版创建完一个Flask项目后,默认会生成一个templates文件夹,如果没有修改模板查找路径,默认会在这个文件夹下寻找模板文件。模板文件可以是任意纯文本格式的文件,如TXT、HTML、XML等,但是为了让项目更规范,也为了与前端开发者更无缝地协作,一般都是用HTML文件来写模板代码。
如果读者用的是非PyCharm Professional版创建的Flask项目,则可以手动创建templates文件夹。
首先在templates文件夹下创建index.html文件,然后输入以下代码。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h1>这是首页</h1> </body> </html>
接下来在视图函数中使用render_template函数渲染index.html模板。在app.py中,将原来的hello_world视图函数修改为以下代码。
from flask import Flask,render_template ... @app.route('/') def index(): return render_template("index.xhtml")
render_template默认会从当前项目的templates文件夹下寻找index.html文件,读取后进行解析,再渲染成HTML代码返回给浏览器。在浏览器中访问http://127.0.0.1:5000,可以看到如图4-1所示的效果。
图4-1 首页渲染模板代码
从图4-1中可以看到,“这是首页”4个字已经是一级标题了,原因是模板中给“这是首页”4个字外面套了一个h1标签,至此我们就完成了一个最简单的模板渲染。
如果想修改模板文件的查找地址,可以在创建app时,给Flask类传递一个关键字参数template_folder指定具体路径,示例代码如下。
app=Flask(__name__,template_folder=r"E:\flask_fullstack\demo04\ mytemplates")
如此操作以后,Flask在寻找模板文件时,就不再从当前项目下的templates文件夹寻找了,而是从template_folder指定的路径寻找。项目在Debug模式开启的前提下再访问http://127.0.0.1:5000,会出现如图4-2所示的错误。
图4-2 模板没有找到
模板没有找到的原因是,在template_folder指定的文件夹下不存在一个叫作index.html的模板,如果想要解决此问题,只需要把templates文件夹下的index.html复制到template_folder指定的文件夹下即可。
HTML文件中的有些数据是需要动态地从数据库中加载的,不能直接在HTML中写死。一般的做法是,在视图函数中把数据先提取好,然后使用render_template渲染模板时传给模板,模板再读取并渲染出来。下面新建一个URL与视图函数映射,示例代码如下。
@app.route("/variable") def variable(): hobby = "游戏" return render_template("variable.xhtml",hobby=hobby)
以上代码中渲染了一个variable.html模板,这个模板文件的创建接下来会具体讲解。除模板名称外,还给render_template传递了一个hobby关键字参数,后续在模板中就可以使用这个变量了。
现在再在templates文件夹下创建一个variable.html模板文件(注意:要记得先删掉template_folder参数),然后输入以下代码。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>变量使用</title> </head> <body> <h1>我的兴趣爱好是:{{ hobby }}</h1> </body> </html>
从以上代码中可以看到,把变量放到两对花括号中即可使用变量。项目运行起来后,在浏览器中访问http://127.0.0.1:5000/variable,效果如图4-3所示。
图4-3 变量使用
图4-3中的文字“游戏”是从视图函数中通过render_template传过去的,并不是在HTML中写死的,所以变量的使用可以让同一个HTML模板渲染无数个不同的页面。
字典的键和对象的属性在模板中都可以通过点(.)的形式访问。在variable这个视图函数中添加两个新的变量,分别是字典类型的person,以及类对象类型的user。示例代码如下。
class User: def __init__(self,username,email): self.username = username self.email = email @app.route("/variable") def variable(): hobby = "游戏" person = { "name": "张三", "age": 18 } user = User("李四","xx@qq.com") return render_template("variable.xhtml",hobby=hobby,person=person,user=user)
接下来,再在variable.html模板中通过点(.)的形式访问person的键和user属性。代码如下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>变量使用</title> </head> <body> <h1>我的兴趣爱好是:{{ hobby }}</h1> <p>person的姓名是:{{ person.name }},person的年龄是:{{ person.age }}</p> <p>user的用户名是:{{ user.name }},user的邮箱是:{{ user.email }}</p> </body> </html>
在浏览器中重新访问http://127.0.0.1:5000/variable,效果如图4-4所示。
字典键和对象的属性也都可以通过中括号的形式获取,如以下代码实际上是等价的。
{{ user.name }} {{ user["name"] }}
读者可以自行修改variable.html中获取键和属性值的方式,最终效果是一样的。用点和中括号的形式访问,虽然效果一样,但是也存在以下不同。
图4-4 模板中通过点渲染字典和对象
(1)在模板中有一个变量的使用方式为foo.bar,那么在Jinja2中则按以下方式进行访问。
通过getattr(foo, 'bar')访问,先访问这个对象的属性。
如果没有找到,就通过foo.__getitem__("bar")方式访问,即访问这个对象的键。
如果以上两种方式都没有找到,返回一个undefined对象。
(2)在模板中有一个变量的使用方式为foo["bar"],那么在Jinja2中则按以下方式进行访问。
通过foo.__getitem__("bar")方式访问,即先访问这个对象的键。
如果没有找到,就通过getattr(foo, "bar")方式访问,即访问这个对象的属性。
如果以上都没找到,则返回一个undefined对象。
以上案例中,传递了3个变量到模板中,在变量比较多的情况,首先可以把所有的变量存放到字典中,然后在给render_template传递参数时使用**语法,将字典变成关键字参数,以上的variable视图函数代码可以改写为以下形式。
@app.route("/variable") def variable(): hobby = "游戏" person = { "name": "张三", "age": 18 } user = User("李四","xx@qq.com") context = { "hobby": hobby, "person": person, "user": user } return render_template("variable.xhtml",**context)
以上代码的写法更加直观和简洁,在遇到需要传给模板的变量比较多的情况,都推荐使用这种方式。