tornado:表单和模板

1. 简单示例: Poem Maker Pro

poemmaker.py:

# -*- coding:utf-8 -*-
import os.path

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

#重定向到文件index.html
class IndexHandler(tornado.web.RequestHandler):
	def get(self):
		self.render('index.html')


#读取数据并将数据重定向到poem.html中
class PoemPageHandler(tornado.web.RequestHandler):
	def post(self):
		noun1 = self.get_argument('noun1')
		noun2 = self.get_argument('noun2')
		verb = self.get_argument('verb')
		noun3 = self.get_argument('noun3')
		#将页面重定向到poem.html,并以字典的方式(roads=noun1等甲鱼rroads:noun1)进行传递,则poem.html中可用{{roads}}进行读取
		self.render('poem.html', roads=noun1, wood=noun2, made=verb, difference=noun3)


if __name__ == '__main__':
	#解析命令行
	tornado.options.parse_command_line()
	app = tornado.web.Application(
		handlers=[(r'/', IndexHandler),
					(r'/poem', PoemPageHandler)
				],
		#将模板路径修改未templates,则index.html和poem.html需保存在templates中
		template_path = os.path.join(os.path.dirname(__file__), 'templates')
	)
	http_server = tornado.httpserver.HTTPServer(app)
	http_server.listen(options.port)
	tornado.ioloop.IOLoop.instance().start()
index.html:
<!DOCTYPE html>
<html>
	<head><title>Poem Maker Pro</title></head>
	<body>
		<h1>Enter terms below.</h1>
		<form method='post' action='/poem'>
			<p>Plural noun<br><input type='text' name='noun1'></p>
			<p>Singular noun<br><input type='text' name='noun2'></p>
			<p>Verb (past tense)<br><input type='text' name='verb'></p>
			<p>Noun<br><input type='text' name='noun3'></p>
			<input type='submit'>
		</form>
	</body>
</html>
poem.html:
<!DOCTYPE html>
<html>
	<head><title>Poem Maker Pro</title></head>
	<body>
		<h1>Your poem</h1>
		<p>Two {{ roads }} diverged in a {{ wood }}, and I-<br>
		I took the one less travelled by, <br>
		And that has {{ made }} all the {{difference}}. </p>
	</body>
</html>
运行程序:
python poemmaker.py --port=8000

 则浏览器操作及输出如下:

tornado:表单和模板_第1张图片

tornado:表单和模板_第2张图片

2. 模板语法

    Tornado模板是被Python表达式和控制语句标记的简单文本文件:

备注:使用Ipython

In [1]: from tornado.template import Template

In [2]: content = Template("<html><body><h1>{{ header }}</h1></body></html>")

In [3]: print content.generate(header='Welcome!')
<html><body><h1>Welcome!</h1></body></html>

1. 填充表达式

    我们可以将任何Python表达式放在双大括号中。Tornado将插入一个包含任何表达式计算结果值的字符串到输出中:

In [4]: from tornado.template import Template

In [5]: print Template('{{ 1 + 1 }}').generate()
2

In [6]: print Template("{{ 'scrambled eggs'[-4:] }}").generate()
eggs

In [7]: print Template("{{', '.join([str(x * x) for x in range(10)]) }}").generate()
0, 1, 4, 9, 16, 25, 36, 49, 64, 81

2. 控制流语句

    我们同样可以在Tornado模板中使用Python条件和循环语句。控制语句以{%和%}包围,以{% end %}结尾,并以类似下面的形式被使用:

{% if page is None %}
{% end %}

{% for book in books %}
{% end %}
测试示例:

poemmaker.py:

# -*- coding:utf-8 -*-
import os.path

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

#重定向到文件index.html
class IndexHandler(tornado.web.RequestHandler):
	#post方法是从其他页面中读取数据进行处理,而get是从本页面中读取数据
	def get(self):
		self.render('index.html', show=True, books=['book1', 'book2', 'book3', 'book4'])


if __name__ == '__main__':
	#解析命令行
	tornado.options.parse_command_line()
	app = tornado.web.Application(
		handlers=[(r'/', IndexHandler)
				],
		#将模板路径修改未templates,则index.html需保存在templates中
		template_path = os.path.join(os.path.dirname(__file__), 'templates')
	)
	http_server = tornado.httpserver.HTTPServer(app)
	http_server.listen(options.port)
	tornado.ioloop.IOLoop.instance().start()
index.html:
<!DOCTYPE html>
<html>
	<head><title>Books</title></head>
	<body>
		<form method='post' action='/poem'>
			{% if show %}
				{% for book in books %}
					<li>{{ book }}</li>
				{% end %}
			{% end %}
		</form>
	</body>
</html>
运行程序:
python poemmaker.py --port=8000
浏览器显示如下:

tornado:表单和模板_第3张图片

3. 在模板中使用函数

    Tornado在所有模板中默认提供了一些便利的函数:

escape(s): 替换字符串s中的&,<,>为他们对应的HTML字符。

url_encode(s): 使用urllib.quote_plus替换字符串s中的字符为URL编码形式。

json_encode(val): 将val编码成JSON格式。

squeeze(s): 过滤字符串s,把连续的多个空白字符替换成一个空格。

    也可以使用自己编写的函数(函数名本身就是一个变量):

In [8]: from tornado.template import Template

In [9]: def disemvowel(s):
   ...:     return ''.join([x for x in s if x not in 'aeiou'])
   ...: 

In [10]: disemvowel('george')
Out[10]: 'grg'

In [11]: print Template("my name is {{ d('mortimer') }}").generate(d = disemvowel)
my name is mrtmr

3. 复杂示例

    用户输入两个文本:一个“源”文本和一个“替代”文本。应用会返回替代文本的一个副本,并将其中每个单词替换成源文本中首字母相同的某个单词。

    这个应用文件包括四个文件:main.py, style.css, index.html和munged.html:

main.cy:

# -*- coding:utf-8 -*-
import os.path
import random

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)

#主文件:重定向到index.html
class IndexHandler(tornado.web.RequestHandler):
	def get(self):
		self.render('index.html')


#处理页面的数据
class MungedPageHandler(tornado.web.RequestHandler):
	#将首字母相同的单词放在一个列表中
	def map_by_first_letter(self, text):
		mapped = dict()
		for line in text.split('\r\n'):
			for word in [x for x in line.split(' ') if len(x) > 0]:
				if word[0] not in mapped:
					mapped[word[0]] = []
				mapped[word[0]].append(word)
		return mapped

	#从其他页面中(index.html)中通过get_argument得到数据,经过Python罗辑处理(map_by_first_letter)后,将数据重定向到munged.html中
	def post(self):
		source_text = self.get_argument('source')
		text_to_change = self.get_argument('change')
		source_map = self.map_by_first_letter(source_text)
		change_lines = text_to_change.split('\r\n')
		self.render('munged.html', source_map=source_map, change_lines=change_lines, choice=random.choice)



if __name__ == '__main__':
	tornado.options.parse_command_line()
	app = tornado.web.Application(
		handlers = [(r'/', IndexHandler),
					(r'/poem', MungedPageHandler)
		],
		#html文件放在templates中
		template_path = os.path.join(os.path.dirname(__file__), 'templates'),
		#css文件放在static中
		static_path = os.path.join(os.path.dirname(__file__), 'static'),
		debug = True
	)
	http_server = tornado.httpserver.HTTPServer(app)
	http_server.listen(options.port)
	tornado.ioloop.IOLoop.instance().start()
index.html:
<!DOCTYPE html>
<html>
	<head>
		<link rel="stylesheet" type="text/css" href="{{ static_url("style.css") }}">
		<title>The Alpha Munger</title>
	</head>
	<body>
		<h1>The Alpha Munger</h1>
		<p>Enter two texts below. The replacement text will have its words
			replaced by words beginning with the same letter in the source text.</p>
		<form method="post" action="/poem">
			<p>Source text<br>
				<textarea rows=4 cols=55 name="source"></textarea>
			</p>	
			<p>Text for replacement<br>
				<textarea rows=4 cols=55 name="change"></textarea>
			</p>
			<input type="submit">
		</form>
	</body>
</html>

munged.html:

<!DOCTYPE html>
<html>
	<head>
		<link rel="stylesheet" href="{{ static_url("style.css") }}">
		<title>The Alpha Munger</title>
	</head>
	<body>
		<h1>Your text</h1>
		<p>
			{% for line in change_lines %}
				{% for word in line.split(' ') %}
					{% if len(word) > 0 and word[0] in source_map %}
						<span class = "replaced"
							title = "{{ word }}">{{ choice(source_map[word[0]]) }}</span>
					{% else %}
						<span class = "unchanged" title = "unchanged">{{ word }}</span>
					{% end %}
				{% end %}
					<br>
			{% end %}
		</p>	
	</body>
</html>
style.css:
body {
	font-family: Helvetica, Arial, sans-serif;
	width: 600px;
	margin: 0 auto;
}
.replaced:hover { color: #00f;}

1. 使用static_url生成静态URL

    Tornado模板模块提供了一个叫做static_url的函数来生成static目录下文件的URL:

<link rel="stylesheet" href="{{ static_url("style.css") }}">
这个对static_url的调用生成了URL的值,并渲染输出类似下面的代码:
<link rel="stylesheet" href="/static/style.css?v=ab12">
    那为什么使用static_url而不是在模板中硬编码呢?有以下原因:

1) static_url函数创建了一个基于文件内容的hash值,并将其添加到URL(查询字符串的参数v)。这个hash值确保浏览器总是加载一个文件的最新版而不是之前的缓存版本。

2) 我们可以改变自己应用URL的结构,而不需要改变模板的代码。(比如之前定义css文件存放在static文件夹下,我们可以将css文件放在newStatic文件夹下,然后修改路径即可)

浏览器输入输出如下:

tornado:表单和模板_第4张图片

tornado:表单和模板_第5张图片


你可能感兴趣的:(tornado:表单和模板)