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.
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.
** 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.
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.
Here, we are passing the string Hironsan as the name.
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.
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.
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.
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.
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.
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.
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.
Recommended Posts