热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

tornado项目搭建_Tornado简单入门教程(一)——Demo1

前面的话Demo1是一个简单的博客系统(。什么网站都叫系统)。我们从这个简单的系统入手,去了解PTM网站的内部逻辑,并记住一些“规则”,方

前面的话

Demo1是一个简单的博客系统(=。=什么网站都叫系统)。我们从这个简单的系统入手,去了解P+T+M网站的内部逻辑,并记住一些“规则”,方便我们进一步自己开发。

“规则”这个词特意打上了双引号,目的是想借此声明一点:本教程内不会将各语句背后的原理逐一讲明(事实上我也讲不清楚哈哈)。我的着重点将在“怎样快速学会使用这个‘框架’去搭建我们想要的网站”,即“怎样快速上手一个工具”。由于本人在技术上研究不深入不细致,所以用词或者内容上难免有不规范或错误之处,能理解的就自行理解哈。当然愿意斧正的欢迎指出。

对了,本教程默认读者是有web开发基础的,明白“渲染”、“get请求”、“post请求”等分别是什么意思。

讲解模式

基本的是:

列出项目目录结构

展示源码,通过部分源码注释(红色字)讲解

列表项目

根据网站逻辑结合“代码回顾”进行讲解

希望大家复制源码(记得把红字注释删除)根据项目目录结构创建项目,或者直接将附件中的代码包拷到你的项目目录,跟着讲解一步一步试验。

OK,开始。

Demo1项目目录结构

demo1

demo.py

-static

-css

style.css

-img

bg.jpg

logo.png

-templates

index.html

blog.html

源码

demo.py

#!/usr/bin/env python

# -*- coding: utf-8 -*-

#用于规定字符编码,想要中文正常最好就加上这句

import os.path

import tornado.auth

import tornado.escape

import tornado.httpserver

import tornado.ioloop

import tornado.options

import tornado.web

from tornado.options import define, options

#巴拉巴拉import一大堆tornado的东西,反正都有用,原封不动即可

import pymongo

#这里是导入MongoDB

define(“port”, default=8002, help=”run on the given port”, type=int)

#定义监听的端口,随便挑个喜欢的数字吧

class Application(tornado.web.Application):

def __init__(self):

handlers = [

(r”/”, MainHandler),

(r”/blog”, BlogHandler),

]

settings = dict(

template_path=os.path.join(os.path.dirname(__file__), “templates”),

static_path=os.path.join(os.path.dirname(__file__), “static”),

debug=True,

)

conn = pymongo.Connection(“localhost”, 12345)

self.db = conn[“demo”]

tornado.web.Application.__init__(self, handlers, **settings)

class MainHandler(tornado.web.RequestHandler):

def get(self):

self.render(“index.html”,)

def post(self):

import time

title = self.get_argument(‘title’, None)

content = self.get_argument(‘content’, None)

blog = dict()

if title and content:

blog[‘title’] = title

blog[‘content’] = content

blog[‘date’] = int(time.time())

coll = self.application.db.blog

coll.insert(blog)

self.redirect(‘/blog’)

self.redirect(‘/’)

class BlogHandler(tornado.web.RequestHandler):

def get(self):

coll = self.application.db.blog

blog = coll.find_one()

if blog:

self.render(“blog.html”,

page_title = blog[‘title’],

blog = blog,

)

else:

self.redirect(‘/’)

def main():

tornado.options.parse_command_line()

http_server = tornado.httpserver.HTTPServer(Application())

http_server.listen(options.port)

tornado.ioloop.IOLoop.instance().start()

if __name__ == “__main__”:

main()

index.html

B06 Innovation Space

window.setInterval(function() {

go_to();

},

100);

function go_to() {

if( document.getElementById(“myArticle”).style.height <(document.getElementById(“myArticle”).scrollHeight – 4 ) &#43; “px”)

document.getElementById(“myArticle”).style.height &#61; document.getElementById(“myArticle”).scrollHeight &#43; “px”;

}

%E2%80%9D%7B%7B

欢迎访问B06创新实验室的博客

文章标题&#xff1a;

文章正文&#xff1a;

blog.html

{{ page_title }}

%E2%80%9D%7B%7B

欢迎访问B06创新实验室的博客

{{ blog[‘title’] }}

{{ locale.format_date(blog[‘date’], relative&#61;False) }}

{{ blog[‘content’] }}

部署项目

从头开始说。

部署用Python开发的网站&#xff0c;需要在服务器上运行一个主文件&#xff0c;比如demo1的部署:

打开终端&#xff0c;cd到项目文件夹&#xff0c;执行python demo.py命令&#xff0c;此时python就在设定好的默认端口8002运行了我们这个网站。

079125d16ac505671396402ccdd1eb03.png

代码回顾&#xff1a;

define(“port”, default&#61;8002, help&#61;”run on the given port”, type&#61;int)

此时打开浏览器&#xff0c;访问http://127.0.0.1:8002&#xff0c;我们可以发现网站已经可以正常访问。

再看终端窗口&#xff0c;发现已经接收到了一个get请求。

2281b767ee46c3810ac8ee05dfa4db5d.png

服务器是怎么样根据我们的请求然后输出给我们相应页面的呢&#xff1f;

Handlers 和 settings

代码回顾&#xff1a;

class Application(tornado.web.Application):

def __init__(self):

handlers &#61; [

(r”/”, MainHandler),

(r”/blog”, BlogHandler),

]

settings &#61; dict(

template_path&#61;os.path.join(os.path.dirname(__file__), “templates”),

static_path&#61;os.path.join(os.path.dirname(__file__), “static”),

debug&#61;True,

)

conn &#61; pymongo.Connection(“localhost”, 12345)

self.db &#61; conn[“demo”]

tornado.web.Application.__init__(self, handlers, **settings)

我们看到在Application中初始化了两个东西(数据库连接另说)&#xff0c;分别是handlers和settings。

顾名思义settings就是项目的各种设置&#xff0c;其中template_path用于指定我们之后要渲染的html文件的文件夹位置&#xff0c;而static_path用于指定之后要用的的一些引用文件(如css文件、js文件、图片等)的文件夹位置 (我偏不解释debug是干什么的:-) )。

handler&#xff0c;我百度翻译了一下&#xff0c;是“处理者”的意思。它的作用就是处理我们向服务器提交的请求。怎么处理呢&#xff1f;

以(r”/”, MainHandler)为例&#xff0c;双引号中间是要访问页面的相对路径&#xff0c;而后面的XxxHandler表示这个路径对应的“处理者类”。初始化如上handlers后&#xff0c;当我们访问http://127.0.0.1:8002/时&#xff0c;我们的请求会被交给MainHandler处理&#xff1b;同样的&#xff0c;当我们访问http://127.0.0.1:8002/blog时&#xff0c;我们的请求将会被交给BlogHandler处理。也就是说handlers用于设定url与处理类间的映射关系。

在之后的几个demo里面&#xff0c;通过对更多handler的设置&#xff0c;我们会慢慢对handler了解得更清楚一些&#xff0c;不要着急。反正大概意思就是一个网址对应一个handler呗。

数据库连接

代码回顾&#xff1a;

class Application(tornado.web.Application):

……

conn &#61; pymongo.Connection(“localhost”, 12345)

self.db &#61; conn[“demo”]

tornado.web.Application.__init__(self, handlers, **settings)

然后说一下这个部分。聪明的人一看就知道这是数据库连接嘛。

第一句&#xff1a;参数一&#xff0c;数据库服务器地址&#xff0c;我们现在是本地服务器所以用localhost&#xff1b;参数二&#xff0c;端口号&#xff0c;端口号当然是你本地MongoDB使用的端口号。这样就连接上MongoDB了。

第二句&#xff1a;self.db &#61; conn[“demo”]&#xff0c;选择一个数据库&#xff0c;把数据库名字放在双引号中间。我的数据库就叫做demo。最后一句就是把之前的设置都初始化嘛&#xff0c;init就是初始化&#xff0c;聪明人都懂的。

服务器处理请求

OK&#xff0c;回过头来&#xff0c;刚才说到当用户访问一个页面的时候&#xff0c;根据我们初始化的handler&#xff0c;服务器会将不同的请求分发给不同的处理类进行处理。

我们的Demo1包含两个页面。首页有一个表单&#xff0c;提交表单后跳转至博客页面。我们先来看看访问首页时是怎么处理的。

当我们访问http://127.0.0.1:8002/时&#xff0c;我们的请求会被交给MainHandler处理&#xff0c;即执行这个类里对应的内容。

代码回顾&#xff1a;

class MainHandler(tornado.web.RequestHandler):

处理类的定义规则是class XxxxHandler(tornado.web.RequestHandler)。Request请求&#xff0c;Handler处理者&#xff0c;处理请求的一个类嘛。括号里面的东西肯定跟tornado、跟网络什么的有关&#xff0c;乖乖地复制就好了。

代码回顾&#xff1a;

def get(self):#用于处理get请求&#xff0c;默认参数是self

self.render(“index.html”,)

def post(self):#用于处理post请求&#xff0c;默认参数是self

import time

title &#61; self.get_argument(‘title’, None)

content &#61; self.get_argument(‘content’, None)

blog &#61; dict()

if title or content:

blog[‘title’] &#61; title

blog[‘content’] &#61; content

blog[‘date’] &#61; int(time.time())

coll &#61; self.application.db.blog

coll.insert(blog)

self.redirect(‘/blog/’)

self.redirect(‘/’)

我们看到MainHandler类里定义了get和post两个方法。

学习tornado让我很感动的一点就是&#xff0c;它让我明白了其实我们在访问网页的时候归根结底就是向网站发出了两种请求(这个认识可能比较浅薄)。

一种是get请求&#xff0c;即打开某个页面。

另一种是post请求&#xff0c;即向某个页面提交表单(数据)。

在tornado中&#xff0c;默认使用get和post函数分别处理两种请求。所以当我们访问http://127.0.0.1:8002/时&#xff0c;服务器就会执行MainHandler中的get函数。

代码回顾&#xff1a;

def get(self):

self.render(“index.html”,)

render就是渲染的意思。这一句就是&#xff1a;在浏览器中渲染出index.html这个文件的内容。index.html文件在哪里呢&#xff1f;从项目目录结构中可以看到&#xff0c;它在templates文件夹中。还记得settings中定义的templates_path吗&#xff1f;我们在render()中的双引号内填入templates文件夹中文件的相对路径即可&#xff0c;服务器会根据templates_path自动补全路径&#xff0c;找到文件&#xff0c;并将之渲染出来。

插一句&#xff1a;在用tornado开发时&#xff0c;我们常用的目录结构正如demo1的目录结构。根目录下放置python文件&#xff0c;templates文件夹中放置html文件&#xff0c;static文件夹中放置引用文件。

所以&#xff0c;当我们访问http://127.0.0.1:8002/时&#xff0c;最终看到的就是下图&#xff1a;

63171aeb8acab52d54263c0e095c0310.png

代码回顾&#xff1a;

此时&#xff0c;我们看到了首页的表单。来看看index.html的源码&#xff1a;表单的提交方式是post&#xff1b;请求的页面(action)没有填写&#xff0c;表示提交到当前页面。现在将表单填充&#xff0c;点击发布。

d5ac80ad37936c4c9d0bc7fca13c3723.png

此时查看终端窗口&#xff0c;我们发现&#xff0c;服务器收到了一个post请求。

65341c80ab2feb7a66a30e3523919783.png

因为表单仍提交到当前页面&#xff0c;所以还是由MainHandler处理。而此时的请求类型为post&#xff0c;所以服务器将执行MainHandler中的post方法。

代码回顾&#xff1a;

def post(self):

import time

title &#61; self.get_argument(‘title’, None)

content &#61; self.get_argument(‘content’, None)

blog &#61; dict()

if title and content:

blog[‘title’] &#61; title

blog[‘content’] &#61; content

blog[‘date’] &#61; int(time.time())

coll &#61; self.application.db.blog

coll.insert(blog)

self.redirect(‘/blog’)

tornado中通过self.get_argument()获取表单数据&#xff0c;其中第一个参数为数据名称&#xff0c;第二个参数为当没有获取到该表单数据时的替代值。

post方法分别获取表单中title和content两个数据&#xff0c;进行简单的判断&#xff0c;当二者均不为空时&#xff0c;将其存入预定义的blog变量中&#xff0c;并且给blog[‘date’]赋值为当前的时间戳。

import time载入时间相关的的一个类&#xff0c;time.time()获取当前时间戳。 coll &#61;

self.application.db.blog获取数据库中的名为blog的collection。

coll.insert(blog)将blog变量插入collection中。

self.redirect(‘/blog’)页面跳转至博客页。在使用redirect函数时&#xff0c;参数为页面相对路径。

简单来说&#xff1a;post方法接收了表单数据并将其插入对应数据集中&#xff0c;然后页面跳转到博客页。

页面跳转&#xff0c;本质就是访问跳转后的页面&#xff0c;即向此页面发送get请求。我们看一下终端窗口&#xff1a;

885d1ab6b2cb31d68da06a9e0159d1ab.png

也就是说self.redirect(‘/blog’)这一句&#xff0c;就是访问http://127.0.0.1:8002/blog&#xff0c;服务器得到get请求&#xff0c;然后让BlogHandler对其进行处理&#xff0c;执行get方法。

代码回顾&#xff1a;

def get(self):

coll &#61; self.application.db.blog

blog &#61; coll.find_one()

if blog:

self.render(“blog.html”,

page_title &#61; blog[‘title’],

blog &#61; blog,

)

else:

self.redirect(‘/’)

那我们看看函数内容。

coll &#61; self.application.db.blog依旧是获取名字为blog的数据集 blog &#61;

coll.find_one()获取一条数据。因为我们是一个最简版的demo&#xff0c;所以就获取一条数据。

if判断数据是否存在&#xff0c;存在则渲染博客页面&#xff0c;不存在则跳转至首页。

render函数第一个参数是要渲染的html文件名&#xff0c;后面的参数为传递到页面的数据&#xff0c;参数间用逗号隔开。

page_title &#61; blog[‘title’]我选择用博客标题作为title&#xff0c;所以传了一个page_title过去。 blog &#61; blog把博客内容传递过去。

什么叫把数据传递到html文件去呢&#xff1f;就是把我们动态获取的数据库数据和html文件一起渲染&#xff0c;把数据在html代码中输出来。

For一个sample:-)&#xff1a;

代码回顾&#xff1a;

{{ blog[‘title’] }}

{{ locale.format_date(blog[‘date’], relative&#61;False) }}

{{ blog[‘content’] }}

在html文件中可以通过特殊语法输出我们传递过来的数据。

{{ 变量名 }}&#xff0c;双大括号中加上变量名&#xff0c;就是输出该变量。比如&#xff1a;{{ blog[‘title’] }}就是输出blog中的title值&#xff1b;{{blog[‘content’] }}就是输出blog中的content值&#xff1b;还有{{ page_title }}就是输出page_title的值。

(关于Tornado在html文件里面对Python语句的使用方法&#xff0c;我会在另外一篇总结中写出来。链接&#xff1a;《Tornado&#xff0c;在模板里使用Python语句》)

locale.format_date()是一个时间格式化函数。locale.format_date(blog[‘date’], relative&#61;False) }}是将blog[‘date’]的值格式化输出。

所以最终渲染出的页面如下图&#xff1a;

67a61c9c12deb6873e095505da2dc3bd.png

至此&#xff0c;一个最简单的博客系统就完成了。



推荐阅读
  • 本文探讨了如何通过优化 DOM 操作来提升 JavaScript 的性能,包括使用 `createElement` 函数、动画元素、理解重绘事件及处理鼠标滚动事件等关键主题。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 解决JavaScript中法语字符排序问题
    在开发一个使用JavaScript、HTML和CSS的Web应用时,遇到从SQLite数据库中提取的法语词汇排序不正确的问题,特别是带重音符号的字母未按预期排序。 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 如何在Django框架中实现对象关系映射(ORM)
    本文介绍了Django框架中对象关系映射(ORM)的实现方式,通过ORM,开发者可以通过定义模型类来间接操作数据库表,从而简化数据库操作流程,提高开发效率。 ... [详细]
  • publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ... [详细]
  • JUnit下的测试和suite
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • Requests库的基本使用方法
    本文介绍了Python中Requests库的基础用法,包括如何安装、GET和POST请求的实现、如何处理Cookies和Headers,以及如何解析JSON响应。相比urllib库,Requests库提供了更为简洁高效的接口来处理HTTP请求。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 深入探讨前端代码优化策略
    本文深入讨论了前端开发中代码优化的关键技术,包括JavaScript、HTML和CSS的优化方法,旨在提升网页加载速度和用户体验。 ... [详细]
author-avatar
Posion丶丨
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有