本系列文章是我用Python框架Flask开发Web应用的经验记录.这是第二篇.
该系列文章的目的是建立一个功能完善的微博应用,我决定称它为microblog,虽然这个名字没什么创意. ^_^
一下是该系列所有已发布文章的索引:
概述
如果你已经阅读过上一个章节,那么你应该已经完成了充分的准备工作并且创建了一个很简单的具有如下文件结构的Web应用:
microblog |-flask文件夹 |-<一些虚拟环境的文件> |-app文件夹 | |-static文件夹 | |-templates文件夹 | |-__init__.py文件 | |-views.py文件 |-tmp文件夹 |-run.py文件
亲,想要运行这个程序么?那就运行这个run.py文件,然后在你的浏览器里边打开http://localhost:5000这个地址.
我们在后面的章节会不断地从前一章节结束的地方继续开发我们的应用,所以你要确保你的环境已经正确安装,并且你的应用能够正常运行.
为什么我们需要使用模板系统
让我们来考虑一下,我们接下来怎么样扩展我们的小程序.
我们要在微博应用里边实现一个非常基本的功能,在首页上面显示一个欢迎已登录用户的标题.暂且忽略当前应用里边没有用户的状况,我将会在稍后解决这个问题.
要显示一个美观大方的标题,最简单的方法就是改变我们提供视图的方式来显示一些HTML代码,不如这样子:\
from app import app @app.route('/') @app.route('/index') def index(): user = { 'nickname': 'Miguel' } # fake user return ''' <html> <head> <title>Home Page</title> </head> <body> <h1>Hello, ''' + user['nickname'] + '''</h1> </body> </html>
现在,在你的浏览器里面刷新一下看看,是不是很爽?
如果保持业务逻辑和表现的分离,你的网站结构将会组织的更好。不要不信,如果你用python完成了业务代码,你甚至可以请一个网站设计师帮你完成剩下的部分。模板系统就是帮你实现业务和表现分离的。
让我们完成第一个模板(fileapp/templates/index.html):
<html> <head> <title>{{title}} - microblog</title> </head> <body> <h1>Hello, {{user.nickname}}!</h1> </body> </html>如你所见,我们只是写了一个普通的HTML页面,唯一跟HTML有区别的就是里面掺杂了一些以 {{ ... }} 组成的动态内容占位符。
现在让我们来看看视图函数中是如何处理这个模板的(fileapp/views.py):
from flask import render_template from app import app @app.route('/') @app.route('/index') def index(): user = { 'nickname': 'Miguel' } # fake user return render_template("index.html", title = 'Home', user = user)
测试这段程序的重点就是看看模板系统是如何工作的。你可以比较浏览器中渲染后的html页面源码与模板文件源码之间的区别。
在上面的程序中,我们从 Flask 框架 import 了一个叫 render_template 的新函数,并用这个函数来渲染模板。并给这个函数赋予了模板文件名和一些变量作为参数。它将导入的变量替换掉模板中的变量占位符,并返回渲染后的模板。
让我们了解的更深入点。在 Flask 底层,render_template 函数实际上是调用了 Flask 的一个组件: Jinja2 模板处理引擎。是 Jinjia2 用导入的变量替换掉了模板中对应的 {{ ... }} 代码块。
Jinja2 模板系统还支持流程控制语句,我们来尝试一下在模板中添加一个 if 流程控制语句 (fileapp/templates/index.html):
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>Welcome to microblog</title> {% endif %} </head> <body> <h1>Hello, {{user.nickname}}!</h1> </body> </html>现在我们的模板文件有点智能了。如果我们在视图函数中忘了定义页面标题变量 title,它将会使用自已的标题替代。把视图函数中 render_template 里的 title 变量取消试试,看看这个 if 流程语句是如何工作的。
也许用户想在他的主页上展示好友最近写的文章,有点像人人,或者新浪微博那样的好友动态,接下来我们就要看看如何来完成这个功能。
首先,创建用户和文章 (fileapp/views.py):
def index(): user = { 'nickname': 'Miguel' } # fake user posts = [ # fake array of posts { 'author': { 'nickname': 'John' }, 'body': 'Beautiful day in Portland!' }, { 'author': { 'nickname': 'Susan' }, 'body': 'The Avengers movie was so cool!' } ] return render_template("index.html", title = 'Home', user = user, posts = posts)
用数组存储用户的文章,每一个数组元素都是一个字典,如上代码所示,这个dict的key是author和body,用来存储文章的作者和文章内容。当我们决定使用数据库来存储这些信息时,这个字典的key可以隐射为表的一个字段,这里为了给大家演示模板的使用,没有使用数据库相关的技术,简单地使用字典和数组模拟用户和他的好友最近发表的文章。
我们的模板文件现在有了一个新问题。我们刚刚创建了一个包含用户文章的内容数据,这个数组可能包含任意数量的文章。怎样才能让模板根据这个数组的数量自动渲染内容。
要解决这个问题,就需要一个新的流程控制语句:for循环。让我们来把 for循环添加到模板文件 (fileapp/templates/index.html)
<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <h1>Hi, {{user.nickname}}!</h1> {% for post in posts %} <p>{{post.author.nickname}} says: <b>{{post.body}}</b></p> {% endfor %} </body> </html>很简单吧,你还可以在数组中添加更多的内容看看效果。
评论删除后,数据将无法恢复
评论(6)
引用来自“述而不作”的评论
@zzxworldfrom app import app
@app.route('/')
@app.route('/index')
def index():
user = { 'nickname': 'Miguel' } # fake user
return '''
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Hello, ''' + user['nickname'] + '''</h1>
</body>
</html>
末尾应该是少了'''
from app import app
@app.route('/')
@app.route('/index')
def index():
user = { 'nickname': 'Miguel' } # fake user
return '''
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Hello, ''' + user['nickname'] + '''</h1>
</body>
</html>
末尾应该是少了'''