组团学

Tornado 模板

阅读 (189653)

一、模板配置

  • 概述

    使用模板 需要仿照静态资源文件路径设置 向web.Application类的构造函数传递一个名为 template_path的参数 来告诉tornado从文件系统的一个特定位置 提供模板文件

  • 配置如下

    BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([ (r'/',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), debug=True, autoreload=True, )

    我们设置了一个当前应用目录下名为templates的子目录作为template_path的参数。在handler中使用的模板将在此目录中寻找

  • 目录结构

    project/ static/ templates/ common/ index.html manage.py

二、模板渲染

  • render(“模板名称”,**kwargs)

    不传递参数示例

    import tornado.web import tornado.ioloop import os class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") if __name__ == '__main__': BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([ (r'/',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), debug=True, autoreload=True, ) app.listen(8000) tornado.ioloop.IOLoop.current().start()

    传递参数示例

    概述:

    函数向模板中传递的参数 也就是变量 在模板中使用 {{ 变量名称 }} 进行获取值

    处理类代码

    class IndexHandler(tornado.web.RequestHandler): def get(self): userInfo = { 'name':'lucky', 'age':18, 'sex':'man', 'num': 10 } # 传递参数和flask一样 # 一次传递多个值 self.render("index.html",userInfo = userInfo)

    模板文件代码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>首页</h2> <h4>获取传递的参数</h4> <p>{{ userInfo }}</p> <p>{{ userInfo['name'] }}</p> <p>{{ userInfo['sex'] }}</p> <p>{{ userInfo['age'] }}</p> <h5>表达式(也就是可以在变量中进行运算操作)</h5> <p>{{ userInfo['age'] + userInfo['num'] }}</p> <h5>测试如果使用的变量不存在(也就是没有传递)结果为会报错</h5> <p>{{ boy }}</p> </body> </html>

    注意:

    • 如果在模板中使用了未传递的变量 则报错
    • 视图传递给模板的数据
    • 要遵守标识符规则
    • 语法:{{ var }}

三、标签

  • 语法: {% tag %}

  • 说明

    可以在Tornado模板中 使用Python条件和循环语句 标签使用{% 标签名称 %} 来使用

  • 作用

    在输出中创建文本

    控制逻辑和循环

  • if标签

    格式

    {% if ...%} ... {% elif ... %} ... {% else %} ... {% end %}

    示例

    {% if grade >= 90 %} 成绩优秀 {% elif grade >= 80 %} 成绩良好 {% else %} 成绩不太理想 {% end %}
  • for标签

    格式

    {% for xx in xx %} 循环体 {% end %}

    示例

    视图函数代码为:

    class IndexHandler(tornado.web.RequestHandler): def get(self): userInfo = { 'name':'lucky', 'age':18, 'sex':'man', 'num':10, } # 传递参数和flask一样 # 一次传递多个值 self.render("index.html",userInfo = userInfo) class TagHandler(tornado.web.RequestHandler): def get(self): userInfo = { 'name': 'lucky', 'age': 18, 'sex': 'man', 'num': 10, } self.render('test_tag.html',grade=70,userInfo=userInfo)

    模板代码

    <ol> {% for k,v in userInfo.items() %} <li>{{ k }}----{{ v }}</li> {% end %} </ol>
  • 转义

说明:tornado默认开启了模板自动转义功能 防止网站收到恶意攻击

  • 示例

def get(self):
self.render(“index.html”,html=“Hello Lucky”)
```

模板渲染结果为:

`&lt;b&gt;Hello Lucky&lt;/b&gt;`
  • 关闭转义的方式

    第一种 raw 用来输出不被转义的原始格式

    示例

{% raw html %}
```

第二种 设置关闭自动转义功能

在python配置中

```python

app = tornado.web.Application([],
autoescape=None,
)
```

第三种 模板中

```phthon

{% autoescape None %}
```

  • 转义变量

{{ escape(需要转义的变量) }}
```

  • 模板导入 include

    • 概述

      可以将指定的HTML文件 在模板中的某个位置进行导入使用 实现模板代码的复用 以及减轻后期代码的维护

    • 格式

      {% include "路径/模板名称.html" %}
    • 示例

      目录结构

      project/ templates/ common/ header.html footer.html index.html manage.py

      index.html代码如下

      <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'common/header.html' %} <h2>首页</h2> {% include 'common/footer.html' %} </body> </html>

      header.html

      <header> <h4>头部分</h4> </header>

      footer.html

      <footer> <h4>尾部分</h4> </footer>
    • 注意事项

      我们在使用include的时候 会将到入文件内的所有代码都拿过来 所以注意被导入的文件中不要有其它代码的存在 否则都会被导入过来

  • 模板继承

    标签:

    • extends 继承

      格式

      {% extends '父模板.html' %}
      
    • block 使用块填充

      格式:

      {% block '名称' %}
      	...
      {% end %}
      
    • 示例

      目录结构

      project/
      	templates/
          	common/
              	base.html
              index.html
      

      base.html代码如下

      <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}标题{% end %}</title> </head> <body> {% block header %} <h2>页面头部分</h2> {% end %} {% block content %} <h2>页面内容部分</h2> {% end %} </body> </html>

      index.html

      {% extends 'common/base.html' %} {% block title %} 首页 {% end %} {% block header %} <h4>首页</h4> {% end %}

      使用bootstrap创建base模板

      base.html

      <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}标题{% end %}</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> {% block styles %} {% end %} </head> <body> {% block header %} <nav class="navbar navbar-inverse" style="border-radius: 0px;"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Brand</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">首页 <span class="sr-only">(current)</span></a></li> <li><a href="#">发表博客</a></li> </ul> <ul class="nav navbar-nav navbar-right"> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Search</button> </form> <li><a href="#">登录</a></li> <li><a href="#">注册</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">个人资料</a></li> <li><a href="#">头像修改</a></li> <li><a href="#">我的博客</a></li> <li role="separator" class="divider"></li> <li><a href="#">退出登录</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> {% end %} <div class="container"> {% block content %} <h1>你好,Lucky!</h1> {% end %} </div> {% block scripts %} <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) --> <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script> <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> {% end %} </body> </html>
    • 注意

      在子模板中 如果想对父母版中的哪个block的位置进行更改 那么就使用block 名称 进行替换 当替换以后 内容为你替换后的内容 若是没有进行替换 则内容为原内容

四、自定义函数

  • 说明

    在模板中还可以使用一个自己编写的函数 只需要将函数名作为模板的参数传递即可 就像其它变量一样

  • 示例

    处理类中

    # 自定义函数 在模板中进行使用 def my_join(con): return '+'.join(con) class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html",my_join=my_join)

    模板中

    <h4>传递函数在模板中使用</h4> {{ my_join('lucky') }}

五、静态文件

说明:我们的图片、样式、js效果 统称为我们的静态资源文件 需要配置静态资源目录static进行使用

  • 目录结构

    project/ static/ img/ css/ js/ upload/ manage.py
  • static_path

    • 说明:我们可以通过向web.Application类的构造函数传递一个名为static_path的参数来告诉Tornado从文件系统的一个特定位置提供静态文件
  • 配置如下

    BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = tornado.web.Application( [(r'/', IndexHandler)], static_path=os.path.join(BASE_DIR, "static"), )

    static_path 配置了静态资源访问的目录

    • 代码示例

      import tornado.ioloop import tornado.httpserver from tornado.web import RequestHandler, Application import os class IndexHandler(RequestHandler): def get(self): self.render('index.html') if __name__ == "__main__": BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = Application([ (r"/", IndexHandler), ], static_path=os.path.join(BASE_DIR, "static"), template_path=os.path.join(BASE_DIR, "templates"), debug = True, ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000) tornado.ioloop.IOLoop.current().start()

      index.html

      <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/css/test.css"> <script src="/static/js/test.js"></script> </head> <body> <img src="/static/img/test.jpg" alt=""> </body> </html>

      注意:对于静态文件目录的命名,为了便于部署,建议使用static

    • 模板中动态构造

      格式

      {{static_url('plugins/bootstrap/css/bootstrap.min.css')}}

      示例

      <img src="{{static_url('img/a.jpg')}}" alt="">

      解析后

      <img src="/static/img/test.jpg?v=11c671ed35a4611f3576ab4cbe5ee59c" alt="">

      优点

      • static_url 函数创建了一个基于文件内容的hash值 并将其添加到URL末尾(查询字符串的参数v) 这个hash值确保浏览器总是加载一个文件的最新版 而不是之前的缓存版本 无论是在应用到开发阶段 还是在部署环境中 都非常有用 因为用户不必在为了看到最新的页面内容而清除浏览器缓存了
      • 另外一个好处可以动态改变应用URL的结构 而不需要改变模板中的代码 需要配置 static_url_prefix来进行更改 如果你使用它进行了更改 那么模板中不需要改变

      前缀示例

      BASE_DIR = os.path.dirname(__file__) app = tornado.web.Application([ (r'^/$',IndexHandler), ], template_path=os.path.join(BASE_DIR,'templates'), static_path=os.path.join(BASE_DIR,'static'), debug=True, static_url_prefix='/lucky/', )
    • 直接通过url进行访问

      http://127.0.0.1:8000/static/img/test.jpg

  • StaticFileHandler

    • 说明

      • 我们再看刚刚访问页面时使用的路径http://127.0.0.1:8000/static/img/test.jpg,这中url显然对用户是不友好的,访问很不方便。我们可以通过tornado.web.StaticFileHandler来自由映射静态资源文件与其访问的路径url
      • urltornado.web.StaticFileHandler是tornado预置的用来提供静态资源文件的handler
    • 示例

      import os from tornado.web import StaticFileHandler BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = Application( [ (r'^/(.*?)$', StaticFileHandler, {"path":os.path.join(BASE_DIR, "static/img"), "default_filename":"test.jpg"}), (r'^/view/(.*)$', StaticFileHandler, {"path":os.path.join(BASE_DIR, "static/img")}), ], static_path=os.path.join(BASE_DIR, "static"), template_path=os.path.join(BASE_DIR, 'templates'), )

      模板中

      <img src="/static/img/a.jpg" alt=""> <img src="/view/a.jpg" alt=""> <img src="/" alt=""> <img src="/b.jpg" alt="">
    • 参数说明

      path 用来指明提供静态文件的根路径,并在此目录中寻找在路由中用正则表达式提取的文件名

      default_filename 用来指定访问路由中未指明文件名时,默认提供的文件

现在,对于静态文件statics/img/test.jpg,可以通过三种方式进行访问:

  • http://127.0.0.1:8000/static/img/test.jpg
  • http://127.0.0.1:8000/
  • http://127.0.0.1:8000/test.jpg
  • http://127.0.0.1:8000/view/test.jpg

六、文件上传

文件上传注意事项

  • 表单的enctype注意修改在进行文件上传的时候
  • 文件上传的文本域 需要存在name属性值
  • 提交方式为 post

示例

import tornado.web import tornado.ioloop import os class IndexHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') # 处理文件上传内的Handler class UploadHandler(tornado.web.RequestHandler): def get(self): self.render('upload.html') def post(self): # 获取上传过来的文件 files = self.request.files if files: # 取出包含当前上传文件数据的列表 img = files.get('img') # 获取上传文件名称(获取到文件名称 是不是可以自己通过文件名称判断该类型文件是否允许上传 以及生成新的文件唯一名称) filename = img[0]['filename'] img_file = img[0]['body'] # 文件的存储操作 # 拼接文件上传存储路径 path = os.path.join('static/upload',filename) file = open(path,'wb') file.write(img_file) file.close() # 上传成功还可以对文件进行大小缩放 以适应其他场合的使用 self.write('文件上传成功') self.write('来了老弟') if __name__ == '__main__': app = tornado.web.Application([ (r'/',IndexHandler), (r'/upload/',UploadHandler), ], debug=True, autoreload=True, template_path=os.path.join(os.path.dirname(__file__),'templates'), ) app.listen(8000) tornado.ioloop.IOLoop.current().start()

upload.html

{% extends 'common/base.html' %} {% block title %} 文件上传 {% end %} {% block content %} <div class="page-header"><h2>文件上传</h2></div> <form action="/upload/" method="post" enctype="multipart/form-data"> <p><input type="file" name="img"></p> <p><input type="submit" value="上传"></p> </form> {% end %}
需要 登录 才可以提问哦