Introduction to Tornado (2): Introduction to development using templates-Dynamic page generation-

Introduction

In this series, I will introduce how to develop applications with Tornado, which is a web server & web application framework that runs on Python. The contents of this series are as follows.

In this second installment, I will introduce the dynamic page generation using templates.

Target audience

Required environment

Related article

Sample code

Last review

In Previous article, I created the following code to display Hello World.

app.py


import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

The above code makes a GET request to [http: // localhost: 8888 /](http: // localhost: 8888 /), and the get method of MainHandler returns the string "Hello, World" and displays it in the browser. It was to do. However, if only fixed values are returned and displayed as in the above code, it is not possible to create a flexible application that changes the display according to the user's input. To do that, most web application frameworks, including Tornado, have the ability to dynamically generate pages programmatically. So, this time, I will introduce the function to dynamically generate pages in Tornado. The keywords here are the following two.

In the following, we will first discuss templates and template engines, and then actually generate pages dynamically.

Templates and template engine

** A template is a template **. Templates in web application development consist of parts that change and parts that do not. Of these, embed a character string to replace in the changing part, and embed data from the program as needed. At this time, the template engine is used to replace the data. ** In other words, the template engine is a mechanism that replaces the changing character string embedded in the template and creates a new character string **.

Let's take a simple example. The following is an example template.

example1.html


<html>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
    <ul>
      {% for item in items %}
        <li>{{ item }}</li>
      {% end %}
    </ul>
  </body>
</html>

As you can see above, the templates are mostly HTML. ** Tornado templates consist of control structures and expressions embedded in markup. ** This template has some parts that change and some parts that do not. What changes is the part surrounded by {{title}} and {% for%} {% end%} surrounded by curly braces, and what does not change is the part of the HTML tag.

You can create a new string by passing data to the template engine to replace the above template. For example, if you pass ** Fruits List ** as ** {{title}} ** and ** ['apple','orange','grape'] ** as ** items **, each part will be replaced. Will be generated, and the following character string will be generated.

example2.html


<html>
  <head>
    <title>Fruits List</title>
  </head>
  <body>
    <ul>
      <li>apple</li>
      <li>orange</li>
      <li>grape</li>
    </ul>
  </body>
</html>

By making good use of the template function, you will be able to efficiently develop by separating the parts that change and the parts that do not change.

Application to create

This time, we will create an application that displays something like "Hello your name!" When it receives a name. It's a simple application, but through the creation of this application you will understand the basics of dynamic page generation. The image of the application is as follows. スクリーンショット 2015-10-26 16.01.02.png

Here, we are passing the string Hironsan as the name.

Directory structure

Before looking at the code, let's first look at this directory structure. This time, the directory structure is as follows.

.
├── app.py
├── static
│   └── style.css
└── templates
    └── index.html

The major difference from Last time is that there are ** static ** and ** templates ** directories. This time, the style.css file is stored statically and the index.html file is stored in templates. The general usage of these directories is to put HTML files in the templates directory and store CSS files, JavaScript code, images, etc. in the static directory separately.

From the above, the components of this application can be divided into the following three.

Let's start with the Python code.

Python code

The Python code to be executed this time is as follows.

app.py


import os
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        name = self.get_argument('name', 'World')
        self.render('index.html', name=name)

BASE_DIR = os.path.dirname(__file__)

application = tornado.web.Application([
        (r'/', MainHandler),
        ],
        template_path=os.path.join(BASE_DIR, 'templates'),
        static_path=os.path.join(BASE_DIR, 'static'),
)

if __name__ == '__main__':
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

The major differences from the previous code are the following three points.

template_path and static_path

Last time As I explained, the Application object could be used to configure the entire application. By passing template_path and static_path as arguments to this Application object, ** tells the application where the templates and static directories are. ** If you do not pass these, the application will not know where the HTML file is, so loading the template etc. will fail and the following error will occur.

FileNotFoundError: [Errno 2] No such file or directory: '/hogehoge/index.html'

render The write method used last time is a method that takes a character string as an argument and returns that character string as an HTTP response. On the other hand, the ** render method is a method ** that passes the template file and the specified arguments to the template engine and sends the resulting string as a response **. This time, we are passing the arguments as follows.

self.render('index.html', name=name)

The first argument is the template file name, and the second and subsequent arguments are variables to pass to the template. Here, the file name of the template is'index.html', and we are passing name as a variable with the name name. Since we are passing the argument by name, we can refer to it by name in the template. If this is yourname = name, refer to it as yourname in the template.

After all, I set the template_path inside the Application object to tell Tornado where to find the templates directory and load the template file from the render method.

get_argument The ** get_argument method is a method ** for receiving the parameters passed from the client. Tornado's RequestHandler class has a number of built-in methods that are useful. One of them is get_argument. For example, in this case, it is specified as follows.

name = self.get_argument('name', 'World')

The value of the name specified in the first argument of get_argument is obtained from the parameter. If the parameter does not have the name specified in the first argument of the get_argument method, the value of the second argument of the get_argument method is returned. In other words, the value of the second argument sets the default value. If the second argument is not set in get_argument and the name specified in the first argument is not in the parameter, an error will occur.

Next, let's take a look at the html file.

template

The template used for display this time is as follows.

templates/index.html


<html>
  <head>
    <title>Hello Tornado</title>
    <link rel="stylesheet" href="{{ static_url('style.css') }}" />
  </head>
  <body>
    <h1>Hello, {{ name }}!</h1>
  </body>
</html>

Can you see that some parts of the template are enclosed in curly braces? These can be replaced by passing data as needed. {{name}} contains the value passed from the render method, and {{static_url ('style.css')}} contains the path of style.css.

The static_url () method used here ** converts the relative path to the file specified in the method to a URL **. Also, when converting to URL, the value of static_path set in Application object is used. Recall that this time we set the static directory as static_path.

As an example of conversion by the static_url () method, in the case of static_url ('style.css'), it is converted as /static/style.css, and in the case of static_url ('css / style.css'), / static It will be converted to /css/style.css.

Finally, let's take a look at CSS.

CSS file

The CSS file used to specify the HTML style this time is as follows.

static/style.css


body {
  background-color: #FFFFE0;
}

h1 {
  background-color: #99cc00;
}

This CSS file does not use any features specific to Tornado, so I will omit the explanation.

Run

Just like last time, run the following code to start the server.

$ python app.py

Then go to [http: // localhost: 8888 /? Name = yourname](http: // localhost: 8888 /? Name = yourname). You should see "Hello, your name!". Try changing the yourname part of the URL to various strings. You can see that the page is dynamically generated according to the string you passed.

Summary

This time, I introduced the dynamic page generation using the template and the template engine. You can see that you can dynamically generate pages by passing data from the program to the template. This time I put the css file directly under static, but in reality, I often create a css directory or stylesheet directory and put the css file under it. I will talk about the project structure around here. Next time, I'll take a closer look at Tornado templates.

Reference material

Recommended Posts

Introduction to Tornado (2): Introduction to development using templates-Dynamic page generation-
Introduction to Tornado (3): Development using templates [Practice]
Introduction to Discrete Event Simulation Using Python # 1
[PyTorch] Introduction to document classification using BERT
Introduction to Discrete Event Simulation Using Python # 2
Introduction to Python Let's prepare the development environment
Introduction to Tornado (1): Python web framework started with Tornado
[PyTorch] Introduction to Japanese document classification using BERT
Introduction to Scapy ② (ICMP, HTTP (TCP) transmission using Scapy)
Understand Python for Pepper development. -Introduction to Python Box-
Introduction to MQTT (Introduction)
Introduction to Scrapy (1)
Introduction to Scrapy (3)
Introduction to Supervisor
Introduction to Tkinter 1: Introduction
Flask development introduction
Introduction to PyQt
Introduction to Scrapy (2)
[Linux] Introduction to Linux
Introduction to Scrapy (4)
Introduction to discord.py (2)
Introduction to discord.py
Python development environment construction 2020 [From Python installation to poetry introduction]
[Introduction to Python] How to stop the loop using break?
[Introduction to cx_Oracle] (Part 13) Connection using connection pool (client side)
[Introduction to Python] How to write repetitive statements using for statements
What I was addicted to when using Python tornado
[Technical book] Introduction to data analysis using Python -1 Chapter Introduction-