Python Tornado初学笔记之表单与模板(一)

时间:2022-09-05 13:34:19

Tornado中的表单和HTML5中的表单具有相同的用途,同样是用于内容的填写。只是不同的是Tornado中的表单需要传入到后台,然后通过后台进行对模板填充。

模板:是一个允许嵌入Python代码片段的HTML文件。

一、简单模板示例:

  Python主程序:

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) class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html') class PoemPageHandler(tornado.web.RequestHandler):
def post(self):
noun1 = self.get_argument('roads')
noun2 = self.get_argument('wood')
verb = self.get_argument('made')
noun3 = self.get_argument('difference')
self.render('poem.html',roads=roads,wood=wood,made=made,difference=difference) if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers=[(r'/',IndexHandler),(r'/poem',PoemPageHandler)],
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()

  template_path为页面文件存放位置,之后还有static文件夹,在static文件夹中存放静态文件如css文件、图片等。此处的template_path是告诉服务器“我的index.html和poem.html文件就放在了当前程序所在文件夹中的template文件夹中,不要去其他地方找了。”,其实在此处调用了Application的__init__函数。当在Application函数中添加一个debug=True参数时,它调用了一个便利的测试模式:tornado.autoreload模块,此时,一旦主要的Python文件被修改,Tornado将会尝试重启服务器,并且在模板改变时会进行刷新。对于快速改变和实时更新这非常棒,但不要再生产上使用它,因为它将防止Tornado缓存模板!

  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="roads"></p>
<p>Singular noun<br><input type="text" name="wood"></p>
<p>Verb (past tense)<br><input type="text" name="made"></p>
<p>Noun<br><input type="text" name="difference"></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>

  注:此处的模板和Flask中的模板是很相似的。

首先先看一段简单的模板代码:

<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>

  在代码中{{  }}包裹的部分为占位符,它是渲染模板时的实际值(即传入的值)。

  其实在程序中最关键的部分在于主程序中的get_argument()函数,该函数可以从表单中获取用户输入的值,然后通过render函数将用户输入的值传递到模板中,然后在模板中渲染显示。  

noun1 = self.get_argument('roads')
noun2 = self.get_argument('wood')
verb = self.get_argument('made')
noun3 = self.get_argument('difference')
self.render('poem.html', roads=roads, wood=wood, made=made, difference=difference)

  假如用户在表单中输入的roads、wood、made、defference分别为pineapples、grandfather clock、irradiated和supernovae。那么当用户点击提交后,看到的内容便为:

Two pineapples diverged in a grandfather clock, and I—
I took the one less travelled by,
And that has irradiated all the supernovae.

二、填充表达式和控制流语句

  在模板中使用表达式,需要将Python表达式放入{{ }}中,Tornado将插入一个包含任何表达式计算结果值的字符串到输出中。

  例如:

>>> from tornado.template import Template
>>> print(Template('{{ 1+2 }}').generate())
b''
>>> print(Template("{{ 'scrambled eggs'[-4:] }}").generate())
b'eggs'
>>> print(Template("{{ ','.join([str(x*x) for x in range(10)]) }}").generate())
b'0,1,4,9,16,25,36,49,64,81'

  在使用python的控制流语句时,需要将控制流语句放入{% %}中,以{% end %}结尾,它同样支持Python的if、while、for、try。Tornado模板语言的一个最好的东西是在if和for语句块中可以使用的表达式没有限制,同时你也可以在你的控制语句块中间使用{% set foo='bar' %}来设置变量。

  例如:

{% if a is None %}xxx{% end %}

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

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

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

  json_encode(s):将val编码成JSON格式。(在系统底层,这是一个对json库的dumps函数的调用。)

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

  注:在Tornado 2.0中,模板被默认为自动转义(并且可以在Application构造函数中使用autoscaping=None关闭)

三、模板扩展

  Tornado中的块替换可以实现前端代码的重用,Tornado通过extends和block语句支持模板继承,这就让你拥有了编写能够在合适的地方复用的流体模板的控制权和灵活性。

  在使用{% extends “xxx.html”%}时,实际上是从xxx.html文件中继承了xxx.html的内容,当然前提是,xxx.html文件中必须定义了相关的块内容。此语句需要在新的模板文件的头部进行提前声明。

  {% block xxx %}语句压缩了一些当你扩展时可能想要改变的模板元素。在新的模板文件中,直接使用该语句,可以实现对该块内容的覆盖,并将自己需要显示的内容放入相对应的模板块中进行显示。

  例如:

  父模板(部分):

<header>{% block header %}{% end %}</header>

  子模版(部分):

<header>
{% block header %}
<p>Hello World!</p>
{% end %}
</header>

  在父模板中可以使用多个块,然后在子模版中直接进行使用就可以,节省了网站开发的时间。此处给出一个简单的header、body、footer块。

<html>
<body>
<header>
{% block header %}{% end %}
</header>
<content>
{% block body %}{% end %}
</content>
<footer>
{% block footer %}{% end %}
</footer>
</body>
</html>

  注:此处容易忘记{% end %},一定要记得添加该结束语句,否则会ParseError的

  当用户自定义一个Application函数时,在我们定义的__init__方法中,需要创建网站的处理类列表以及一个设置的字典,然后在初始化子类中调用中传递这些值,

  tornado.web.Application.__init__(self,handlers,**settings)),说明:handlers中主要写访问页面时需要调用哪个函数,settings中主要为静态文件、网页文件路径以及其他调试的参数。当然在运行时就需要更改应用方式了。

  用户自定的Application函数:

class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", xxxHandler),#xxxHandler根据自己实际的类名称进行填写
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
debug=True,
)
tornado.web.Application.__init__(self, handlers, **settings)

  原:

http_server = tornado.web.Application(app) #app中为网站的配置

  改:

http_server = tornado.web.Application(Application())#Application中为我们自定义个网站配置,此处将网站的配置写入了一个函数中。

  注:此处不给出一个简单页面的代码是因为,在此处,每个人都可以按照自己的想法仿照前面的例子进行写个简单的代码,然后将上文的内容进行使用,这种方法我个人觉得是一个很好的锻炼方式。

  前文说过,在tornado中会自动转义模板中的内容,把标签转换为相应的HTML实体。这样可以防止后端为数据库的网站被恶意脚本攻击。

  例如设置一个邮箱链接:

{% set mailLink = "<a href="mailto:contact@burtsbooks.com">Contact Us</a>" %}
{{ mailLink }}'

  在tornado中会将该内容在页面源码中显示为:

&lt;a href=&quot;mailto:contact@burtsbooks.com&quot;&gt;Contact Us&lt;/a&gt;

  此时自动转义被运行了,很明显,这无法让人们联系该用户。

  为了处理这种情况,你可以禁用自动转义,一种方法是在Application构造函数中传递autoescape=None,另一种方法是在每页的基础上修改自动转义行为,如下所示:

{% autoescape None %}
{{ mailLink }}

  注:这些autoescape块不需要结束标签,并且可以设置xhtml_escape来开启自动转义(默认行为),或None来关闭

  tornado.escape.linkify():

tornado.escape.linkify(text, shorten=False, extra_params='', require_protocol=False, permitted_protocols=['http', 'https'])[source]

Converts plain text into HTML with links.

For example: linkify("Hello http://tornadoweb.org!") would returnHello <a href="http://tornadoweb.org">http://tornadoweb.org</a>!

Parameters:

shorten: Long urls will be shortened for display.

extra_params: Extra text to include in the link tag, or a callable
taking the link as an argument and returning the extra text e.g. linkify(text, extra_params='rel="nofollow" class="external"'), or: def extra_params_cb(url):
if url.startswith("http://example.com"):
return 'class="internal"'
else:
return 'class="external" rel="nofollow"'
linkify(text, extra_params=extra_params_cb)
require_protocol: Only linkify urls which include a protocol. If
this is False, urls such as www.facebook.com will also be linkified. permitted_protocols: List (or set) of protocols which should be
linkified, e.g. linkify(text, permitted_protocols=["http", "ftp", "mailto"]). It is very unsafe to include protocols such as javascript.

四、Tornado中的UI Module

  UI模块是封装模板中包含的标记、样式以及行为的可复用组件。它所定义的元素通常用于多个模板交叉复用或在同一个模板中重复使用。模块本身是一个继承自Tornado的UIModule类的简单Python类,并定义了一个render方法。当一个模板使用{% module Foo(...) %}标签引用一个模块时,Tornado的模板引擎调用模块的render方法,然后返回一个字符串来替换模板中的模块标签。UI模块也可以在渲染后的页面中嵌入自己的JavaScript和CSS文件,或指定额外包含的JavaScript或CSS文件。你可以定义可选的embedded_javascript、embedded_css、javascript_files和css_files方法来实现这一方法。

  在模板中引入模块时,需要在应用的设置中进行声明,ui_moudles参数期望一个模块名为键、类为值的字典输入来渲染它们。

  简单例子:  

import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.options
import os.path from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int) class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.render('hello.html') class HelloModule(tornado.web.UIModule):
def render(self):
return '<h1>Hello, world!</h1>' if __name__ == '__main__':
tornado.options.parse_command_line()
app = tornado.web.Application(
handlers=[(r'/', HelloHandler)],
template_path=os.path.join(os.path.dirname(__file__), 'templates'),
ui_modules={'Hello': HelloModule}
)
server = tornado.httpserver.HTTPServer(app)
server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()

  当用户访问时,程序首先会先调用HelloHandler类,然后进行跳转至hello.html页面,然后再hello.html页面使用{% module Hello() %}进行显示需要显示的内容。当使用这个module时,会调用ui_modules中的Hello对应的类,然后进行内容反馈。

  hello.html文件内容:

<html>
<head><title>UI Module Example</title></head>
<body>
{% module Hello() %}
</body>
</html>

  这个hello.html模板通过在模块标签自身的位置调用HelloModule返回的字符串进行填充

  如果要用更多的模块,只需要简单地在ui_modules参数中添加映射值。因为模板可以指向任何定义在ui_modules字典中的模块。

五、嵌入JavaScript和CSS

  为了给这些模块提供更高的灵活性,Tornado允许你使用embedded_css和embedded_javascript方法嵌入其他的CSS和JavaScript文件。

  添加本地CSS文件:

def css_files(self):
return "/static/css/newreleases.css"

  添加外部的JavaScript文件:

def javascript_files(self):
return "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"

  当一个模块需要额外的库而应用的其他地方不是必需的时候,这种方式非常有用。比如,你有一个使用JQuery UI库的模块(而在应用的其他地方都不会被使用),你可以只在这个样本模块中加载jquery-ui.min.js文件,减少那些不需要它的页面的加载时间。

  因为模块的内嵌JavaScript和内嵌HTML函数的目标都是紧邻标签,html_body()、javascript_files()和embedded_javascript()都会将内容渲染后插到页面底部,那么它们出现的顺序正好是你指定它们的顺序的倒序。

  如果你有一个模块如下面的代码所示:

class SampleModule(tornado.web.UIModule):
def render(self, sample):
return self.render_string(
"modules/sample.html",
sample=sample
) def html_body(self):
return "<div class=\"addition\"><p>html_body()</p></div>" def embedded_javascript(self):
return "document.write(\"<p>embedded_javascript()</p>\")" def embedded_css(self):
return ".addition {color: #A1CAF1}" def css_files(self):
return "/static/css/sample.css" def javascript_files(self):
return "/static/js/sample.js"

  加载方式为:html_body()最先被编写,它紧挨着出现在标签的上面。embedded_javascript()接着被渲染,最后是javascript_files()

Python Tornado初学笔记之表单与模板(一)的更多相关文章

  1. And Design:拓荒笔记——Form表单

    And Design:拓荒笔记——Form表单 Form.create(options) Form.create()可以对包含Form表单的组件进行改造升级,会返回一个新的react组件. 经 For ...

  2. Symfony2学习笔记之表单

    对于一个Web开发者来说,处理HTML表单是一个最为普通又具挑战的任务.Symfony2集成了一个Form组件,让处理表单变的容易起来.在这一节里,我们将从基础开始创建一个复杂的表单,学习表单类库中最 ...

  3. AngularJS 1&period;2&period;x 学习笔记(表单校验篇)

    https://my.oschina.net/cokolin/blog/526911 摘要: 本文首发于 blog.csdn.net/vipshop_ebs/article/details/39472 ...

  4. Bootstrap学习笔记&lpar;二&rpar; 表单

    在Bootstrap学习笔记(一) 排版的基础上继续学习Bootstrap的表单,编辑器及head内代码不变. 3-1 基础表单 单中常见的元素主要包括:文本输入框.下拉选择框.单选按钮.复选按钮.文 ...

  5. Django学习笔记之表单验证

    表单概述 HTML中的表单 单纯从前端的html来说,表单是用来提交数据给服务器的,不管后台的服务器用的是Django还是PHP语言还是其他语言.只要把input标签放在form标签中,然后再添加一个 ...

  6. 看用Tornado如何自定义实现表单验证

    我们知道,平时在登陆某个网站或软件时,网站对于你输入的内容是有要求的,并且会对你输入的错误内容有提示,对于Django这种大而全的web框架,是提供了form表单验证功能,但是对于Tornado而言, ...

  7. vue学习笔记&lpar;六&rpar;表单输入绑定

    前言 在上一章vue学习笔记(四)事件处理器这一篇博客的内容中,我们已经了解vue是如何绑定事件的,而本篇博客主要讲解的是vue中表单输入的绑定,通常我们自己提交信息的时候都是通过表单将信息到服务器的 ...

  8. iOS开发笔记11&colon;表单键盘遮挡、浮点数价格格式化显示、省市区选择器、View Debugging

    1.表单键盘遮挡 应用场景为一个collectionView上有多个textfield.textView供用户填写信息. 之前输入项较少时,采取的方法比较粗暴,didSelectItemAtIndex ...

  9. 初学structs2,表单验证

    一.简单表单验证示例 structs.xml配置 <struts> <package name="validate" namespace="/valid ...

随机推荐

  1. Centos6安装Gitlab

    安装参考 https://about.gitlab.com/downloads/ 可以从清华的镜像下载安装包, 注意区分自己用的是哪个发行版 https://mirror.tuna.tsinghua. ...

  2. Machine Learning in Action -- 回归

    机器学习问题分为分类和回归问题 回归问题,就是预测连续型数值,而不像分类问题,是预测离散的类别 至于这类问题为何称为回归regression,应该就是约定俗成,你也解释不通 比如为何logistic ...

  3. Js- 菜单

    很简单的JS二级菜单显示,收藏 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  4. Delphi中一些常用的组合键值

    Delphi中一些常用的组合键值  CTRL+A: #1  CTRL+B: #2  CTRL+C: #3  CTRL+D: #4  CTRL+E: #5  CTRL+F: #6  CTRL+G: #7 ...

  5. 关于sg90舵机的,要知道!要注意!

    这类舵机的转向跟频率和占空比相关,两者缺一不可! 1.在一个特定的频率下,特定的占空比使得舵机会转到一个角度,占空比不变,则角度不会不会变化,所以想要舵机动,就要在国定的频率下不断改变占空比. 2.当 ...

  6. Luogu4755 Beautiful Pair 最值分治、主席树

    传送门 整天做一些模板题感觉药丸 设\(val_i\)表示第\(i\)个位置的值 看到区间最大值考虑最值分治.对于当前的区间\([l,r]\),找到区间最大值\(mid\),递归\([l,mid-1] ...

  7. Python-JS基础&lpar;基础结构~函数&rpar;

    程序本质上分为三大结构: 顺序结构.分支结构.循环结构JavaScript中的程序结构也是这样,下面我们来分别介绍JS中的三种基本程序结构:我们上篇博客中介绍到的使用逻辑运算符&&实现 ...

  8. Android应用程序模型:应用程序,任务,进程,线程

    大多数操作系统,在应用程序所寄存的可执行程序映像(如Windows系统里的.exe).它所运行的进程以及和用户交互的图标和应用之间有一种严格的1对1关系.在Android系统里,这些关联要松散得多.并 ...

  9. VS 2017 Region快捷键无法折叠

  10. CLOUDSTACK FOR HYPER-V

    原文地址:http://zhu.vn/archives/1040 我这里是内网测试环境,宿主机为Server 2012R2 ,虚拟化技术为HYPER-V,域环境来的(不是域环境玩不了). 先给宿主机安 ...