Tornado实战-图片上传和图片展示
2018-07-29 本文已影响0人
Python野路子
项目主要部分
- 发现或最近上传的图片页面
- 所关注的用户图片流
- 单个图片详情页面
- 数据库 Database
- 用户档案 User Profile
如何去做
- 从最简单开始,迭代增加功能
- 用户,登陆,关注等
- 数据库保存
- UI 和 Web 界面美化
- 外部连接
- 部署和运行
基本页面
- 发现或最近上传的图片页面 /explore ExploreHandler
- 所关注的用户图片流 / IndexHandler
- 单个图片详情页面 /post/id PostHandler
代码
image.pngapp.py
import tornado.ioloop #开启循环,让服务一直等待请求的到来
import tornado.web #web服务基本功能都封装在此模块中
import tornado.options #从命令行中读取设置
from tornado.options import define,options #导入包
from handlers import main
define('port',default='8000',help='Listening port',type=int) #定义如何接受传进来的东西
class Application(tornado.web.Application): #引入Application类,重写方法,这样做的好处在于可以自定义,添加另一些功能
def __init__(self):
handlers = [
(r'/',main.IndexHandler),
(r'/explore',main.ExploreHandler),
(r'/post/(?P<post_id>[0-9]+)',main.PostHandler), #命名组写法,使用关键字,路由与handler方法不一定顺序一致
(r'/upload',main.UploadHandler)
]
settings = dict(
debug = True, #调试模式,修改后自动重启服务,不需要自动重启,生产情况下切勿开启,安全性
template_path = 'templates', #模板文件目录,想要Tornado能够正确的找到html文件,需要在 Application 中指定文件的位置
static_path = 'static' #静态文件目录,可用于用于访问js,css,图片之类的添加此配置之后,tornado就能自己找到静态文件
)
super(Application,self).__init__(handlers,**settings) #用super方法将父类的init方法重新执行一遍,然后将handlers和settings传进去,完成初始化
app = Application() #实例化
if __name__ == '__main__': #当.py文件被直接运行时,代码块将被运行;当.py文件以模块形式被导入时,代码块不被运行。
tornado.options.parse_command_line()
app.listen(options.port) ##如果一个与define语句中同名的设置在命令行中被给出,那么它将成为全局的options的一个属性 即 options.port 相当于define的url的port
print("Server start on port {}".format(str(options.port))) #提示服务启动占用端口
tornado.ioloop.IOLoop.current().start() #执行ioloop
main.py
import tornado.web
import os
from utils import photo
class IndexHandler(tornado.web.RequestHandler):
"""
Home page for user,photo feeds 主页----所关注的用户图片流
"""
def get(self,*args,**kwargs):
self.render('index.html') #打开index.html网页
class ExploreHandler(tornado.web.RequestHandler):
"""
Explore page,photo of other users 发现页-----发现或最近上传的图片页面
"""
def get(self,*args,**kwargs):
# image_urls = get_images("./static/uploads") #打开指定路径下的文件,或者static/uploads
os.chdir('static') # 用于改变当前工作目录到指定的路径
image_urls = photo.get_images("uploads/thumbs")
os.chdir("..")
self.render('explore.html',image_urls=image_urls)
class PostHandler(tornado.web.RequestHandler):
"""
Single photo page and maybe 单个图片详情页面
"""
def get(self,post_id):
print(post_id)
self.render('post.html',post_id = post_id) #根据正则输入的内容,接收到,打开相应的图片
class UploadHandler(tornado.web.RequestHandler): #上传文件
def get(self,*args,**kwargs):
self.render('upload.html')
def post(self,*args,**kwargs):
file_imgs = self.request.files.get('newImg',None) #获取上传文件数据,返回文件列表
for file_img in file_imgs: #可能同一个上传的文件会有多个文件,所以要用for循环去迭代它
# filename 文件的实际名字,body 文件的数据实体;content_type 文件的类型。 这三个对象属性可以像字典一样支持关键字索引
save_to = 'static/uploads/{}'.format(file_img['filename'])
#以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
with open(save_to,'wb') as f: #二进制
f.write(file_img['body'])
photo.make_thumb(save_to) #同时生成缩略图
self.redirect('/explore')
photo.py
import glob,os
from PIL import Image
def get_images(path): #将某个路径下所有的文件会返回成一个列表,glob支持*?[]这三种通配符
#glob模块的主要方法就是glob,该方法返回所有匹配的文件路径列表(list)
image_urls = glob.glob(path + '/*.jpg') #所有path目录下面为*.jpg的图片路径
return image_urls
#生成缩略图
def make_thumb(path):
im = Image.open(path) #打开图片
im.thumbnail((200,200)) #thumbnail函数接受一个元组作为参数,分别对应着缩略图的宽高,在缩略时,函数会保持图片的宽高比例。
name = os.path.basename(path) #返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。
filename,ext = os.path.splitext(name) #分离文件名与扩展名;默认返回(fname,fextension)元组,可做分片操作
#save to filename_200x200.jpg
im.save('static/uploads/thumbs/{}_{}x{}{}'.format(filename,200,200,ext))
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title%}Tornado Title{% end %}</title>
</head>
<body>
{% block content %}base content{% end %}
</body>
</html>
index.html
{% extends 'base.html' %} #继承base.html
{% block title %} index page {% end %}
{% block content %}index content
{% for num in range(1,5) %}
<a href="/post/{{num}}">
<img src="{{static_url('images/{}.jpg'.format(num))}}" /> <!-- 使用此方法时,Tornado 会自动地给静态文件添加版本号,如果版本号更改了,浏览器会自动的缓存新的静态文件-->
</a>
{% end %}
{% end %}
upload.html
{% extends 'base.html' %}
{% block title %} uploads page{% end %}
{% block content %} content page
<!--如果表单需要上传文件,需要设置enctype="multipart/form-data" 否则文件无法找到 -->
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="newImg">
<input type="submit">
</form>
{% end %}
explore.html
{% extends 'base.html' %}
{% block title %} explore page {% end %}
{% block content %} explore content
{% for url in image_urls %}
<!--<img src="{{url}}" />-->
<!--<img src="{{static_url(url)}}" width="200"/>-->
<img src="{{static_url(url)}}"/>
{% end %}
{% end %}
post.html
{% extends 'base.html' %}
{% block title %} post page {% end %}
{% block content %}
post of {{post_id}} content
<img src="{{static_url('images/{}.jpg'.format(post_id))}}" width="300"/>
{% end %} #获取post_id并write到网页
页面效果图
image.pngimage.png
image.png
要点
上传表单和文件保存
- self.request.files 的使用
- Python 操作文件,写入数据
用简单的目录检索来展示
使用 Python 标准库 glob
缩略图生成
pip install pillow
使用 PIL