1. 程式人生 > >5 圖片上傳和展示完善

5 圖片上傳和展示完善

回顧上節內容

  • 使用資料庫的登入和註冊
  • 使用資料庫保圖片 url 和展示

改進圖片上傳

路徑處理

對儲存的路徑和縮圖路徑,URL 的處理

photo.py

class ImageSave(object):
   """
   儲存圖片
   """
   upload_dir = 'uploads'
   thumb_dir = 'thumbs'
   size = (200, 200)

   def __init__(self, static_path, name):
      self.static_path = static_path  # static
self.oldname = name # 701728.jpg self.newname = self.gen_new_name() def gen_new_name(self): """ 生成隨機唯一的字串(檔名) :return: """ _, ext = os.path.splitext(self.oldname) return uuid.uuid4().hex + ext # 圖片的url: uploads / 1202983.jpg @property def image_url
(self): return os.path.join(self.upload_dir, self.newname) # 圖片上傳後的儲存路徑 static / uploads / 1202983.jpg @property def upload_path(self): return os.path.join(self.static_path, self.image_url) # 縮圖的url:uploads / thumbs / 1202983_200x200.jpg @property def thumb_url(self): filename,
ext = os.path.splitext(self.newname) thumb_name = '{}_{}x{}{}'.format(filename, *self.size, ext) return os.path.join(self.upload_dir, self.thumb_dir, thumb_name) # 儲存圖片 def save_image(self, content): with open(self.upload_path, 'wb') as f: f.write(content) # 生成縮圖 def make_thumbs(self): im = Image.open(self.upload_path) im.thumbnail(self.size) # static / uploads / thumbs / 1202983.jpg save_thumb_to_ = os.path.join(self.static_path, self.thumb_url) im.save(save_thumb_to_, 'JPEG')

main.py

class UploadHandler(AuthBaseHandler):
   """
      接受圖片上傳
      """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      self.render('upload.html')

   def post(self, *args, **kwargs):
      # 提取表單中‘name’為‘newimg’的檔案元資料   獲取上傳檔案資訊
      img_files = self.request.files.get('newimg')

      if img_files:
         post_id = 0
         for img in img_files:
            # 儲存的圖片的目錄 名字
            image_saver = ImageSave(self.settings['static_path'], img['filename'])
            # 儲存圖片
            image_saver.save_image(img['body'])

            # 生成縮圖  ./ static / uploads /thumbs/ 701728_200x200.jpg
            image_saver.make_thumbs()

            # 儲存圖片的使用者 大圖地址 縮圖地址  把url存到資料庫
            post = Posts.add_post_for(self.current_user, image_saver.image_url, image_saver.thumb_url)
            post_id = post.id

         self.redirect('post/{}'.format(post_id))
      else:
         self.write({'msg': 'empty form data'})

上傳圖片名字唯一

用 uuid 庫生成

uuid.uuid4().hex 



In [2]: uuid.uuid4()
Out[2]: UUID('c27cbc55-c544-4375-a0d8-ed7f50cfc2aa')

In [3]: uuid.uuid4().hex
Out[3]: '17d9d7327d624edf99117f7f2c43d596'

改進首頁 /

顯示使用者自己上傳的圖片,可以點選檢視具體圖片頁

main.py

class IndexHandler(AuthBaseHandler):
   """
   首頁
   """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      post_list = get_post_for(self.current_user)
      self.render('index.html', post_list=post_list)

utils/account.py

def get_post_for(username):
   """
   獲取使用者上傳的圖片資訊
   :param username:
   :return:
   """
   user = session.query(Users).filter_by(name=username).first()
   if user:
      return user.posts
   else:
      return []

index.html

{% extends 'base.html' %}

{% block title %}
    index page
{% end %}

{% block content %}
    <p><a href="/logout">登出</a></p>
    {% for post in post_list %}
        <a href="post/{{ post.id }}">
            <img src="{{ static_url(post.image_url) }}" width="666">
        </a>
    {% end %}

{% end %}

改進發現頁 /explore

顯示所有圖片縮圖檢視,可以點選檢視具體圖片頁

main.py

class ExploreHandler(AuthBaseHandler):
   """
   發現頁
   """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      post_list = get_post_all()
      self.render('explore.html', post_list=post_list)

utils/account.py

def get_post_all():
   """
   獲取所有圖片資訊(降序)
   :return:
   """
   post_list = session.query(Posts).order_by(Posts.id.desc()).all()
   return post_list

explore.html

{% extends 'base.html' %}

{% block title %}
    explore page
{% end %}

{% block content %}
      <p><a href="/logout">登出</a></p>
     {% for post in post_list %}
        <a href="post/{{ post.id }}">
            <img src="{{ static_url(post.thumb_url) }}">
        </a>
    {% end %}
{% end %}

改進單獨頁 /post/2

顯示具體圖片頁面

main.py

class PostHandler(AuthBaseHandler):
   """
   詳情頁
   """

   @tornado.web.authenticated
   def get(self, post_id):
      post = get_post(post_id)
      if not post:
         self.write('post id is not exists')
      else:
         self.render('post.html', post=post)

utils/account.py

def get_post(post_id):
   """
   獲取使用者的特定圖片
   :param post_id:
   :return:
   """
   post = session.query(Posts).filter_by(id=post_id).first()
   return post

post.html

{% extends 'base.html' %}

{% block title %}
    post page
{% end %}

{% block content %}
    <img src="{{ static_url(post.image_url)}}" width="560">
    upload by {{ post.user.name }}
{% end %}

作業

進行圖片上傳的改進和完善3個頁面

完整程式碼

main.py

import tornado.web
from utils import photo
from models.account import Posts
from pycket.session import SessionMixin
from utils.account import get_post_for, get_post, get_post_all
from utils.photo import ImageSave
import os


class AuthBaseHandler(tornado.web.RequestHandler, SessionMixin):
   def get_current_user(self):
      return self.session.get('tudo_user_info')


class IndexHandler(AuthBaseHandler):
   """
   首頁
   """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      post_list = get_post_for(self.current_user)
      self.render('index.html', post_list=post_list)


class ExploreHandler(AuthBaseHandler):
   """
   發現頁
   """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      post_list = get_post_all()
      self.render('explore.html', post_list=post_list, current_user=self.current_user)


class PostHandler(AuthBaseHandler):
   """
   詳情頁
   """

   @tornado.web.authenticated
   def get(self, post_id):
      post = get_post(post_id)
      if not post:
         self.write('post id is not exists')
      else:
         self.render('post.html', post=post)


class UploadHandler(AuthBaseHandler):
   """
      接受圖片上傳
      """

   @tornado.web.authenticated
   def get(self, *args, **kwargs):
      self.render('upload.html')

   def post(self, *args, **kwargs):
      # 提取表單中‘name’為‘newimg’的檔案元資料   獲取上傳檔案資訊
      img_files = self.request.files.get('newimg')

      if img_files:
         post_id = 0
         for img in img_files:
            # 儲存的圖片的目錄 名字
            image_saver = ImageSave(self.settings['static_path'], img['filename'])
            # 儲存圖片
            image_saver.save_image(img['body'])

            # 生成縮圖  ./ static / uploads /thumbs/ 701728_200x200.jpg
            image_saver.make_thumbs()

            # 儲存圖片的使用者 大圖地址 縮圖地址  把url存到資料庫
            post = Posts.add_post_for(self.current_user, image_saver.image_url, image_saver.thumb_url)
            post_id = post.id

         self.redirect('post/{}'.format(post_id))
      else:
         self.write({'msg': 'empty form data'})

utils/account.py

import hashlib
from models.account import Users, session, Posts
from datetime import datetime


def hashed(passwd):
   return hashlib.md5(passwd.encode('utf8')).hexdigest()


def authenticate(username, password):
   """
   登入認證
   :param username:
   :param password:
   :return:
   """
   if username and password:
      # 獲取資料庫中username對應的密碼
      user_passwd = Users.get_passwd(username)
      # 如果使用者存在 密碼匹配
      if user_passwd and user_passwd == hashed(password):
         return True
   return False


def register(username, password, email):
   """
   註冊
   :param username:
   :param password:
   :param email:
   :return:
   """
   # 檢視使用者是否存在於資料庫中
   if Users.is_exists(username):
      return {'msg': '使用者已存在'}
   hash_passwd = hashed(password)
   # 新增使用者到資料庫
   Users.add_user(username, hash_passwd, email)
   return {'msg': 'ok'}


def save_last_login(username):
   """
   # 儲存使用者username最後登入時間
   :param username:
   :return:
   """
   t = datetime.now()
   print("user {} login at {}".format(username, t))
   session.query(Users).filter_by(name=username).update({Users.last_login: t})
   session.commit()


def get_post_for(username):
   """
   獲取使用者上傳的圖片資訊
   :param username:
   :return:
   """
   user = session.query(Users).filter_by(name=username).first()
   if user:
      return user.posts
   else:
      return []


def get_post_all():
   """
   獲取所有圖片資訊(降序)
   :return:
   """
   post_list = session.query(Posts).order_by(Posts.id.desc()).all()
   return post_list


def get_post(post_id):
   """
   獲取使用者的特定圖片
   :param post_id:
   :return:
   """
   post = session.query(Posts).filter_by(id=post_id).first()
   return post

photo.py

import os
import glob
from PIL import Image
import uuid


class ImageSave(object):
   """
   儲存圖片
   """
   upload_dir = 'uploads'
   thumb_dir = 'thumbs'
   size = (200, 200)

   def __init__(self, static_path, name):
      self.static_path = static_path  # static
      self.oldname = name  # 701728.jpg
      self.newname = self.gen_new_name()

   def gen_new_name(self):
      """
      生成隨機唯一的字串(檔名)
      :return:
      """
      _, ext = os.path.splitext(self.oldname)
      return uuid.uuid4().hex + ext

   # 圖片的url: uploads / 1202983.jpg
   @property
   def image_url(self):
      return os.path.join(self.upload_dir, self.newname)

   # 圖片上傳後的儲存路徑 static / uploads / 1202983.jpg
   @property
   def upload_path(self):
      return os.path.join(self.static_path, self.image_url)

   # 縮圖的url:uploads / thumbs / 1202983_200x200.jpg
   @property
   def thumb_url(self):
      filename, ext = os.path.splitext(self.newname)
      thumb_name = '{}_{}x{}{}'.format(filename, *self.size, ext)
      return os.path.join(self.upload_dir, self.thumb_dir, thumb_name)

   # 儲存圖片
   def save_image(self, content):
      with open(self.upload_path, 'wb') as f:
         f.write(content)

   # 生成縮圖
   def make_thumbs(self):
      im = Image.open(self.upload_path)
      im.thumbnail(self.size)
      # static / uploads / thumbs / 1202983.jpg
      save_thumb_to_ = os.path.join(self.static_path, self.thumb_url)
      im.save(save_thumb_to_, 'JPEG')

index.html

{% extends 'base.html' %}

{% block title %}
    index page
{% end %}

{% block content %}
    <p><a href="/logout">登出</a></p>
    {% for post in post_list %}
        <a href="post/{{ post.id }}">
            <img src="{{ static_url(post.image_url) }}" width="666">
        </a>
    {% end %}

{% end %}

explore.html

{% extends 'base.html' %}

{% block title %}
    explore page
{% end %}

{% block content %}
      <p><a href="/logout">登出</a></p>
     {% for post in post_list %}
        <a href="post/{{ post.id }}">
            <img src="{{ static_url(post.thumb_url) }}">
        </a>
    {% end %}
{% end %}

post.html

{% extends 'base.html' %}

{% block title %}
    post page
{% end %}

{% block content %}
    <img src="{{ static_url(post.image_url)}}" width="560">
    upload by {{ post.user.name }}
{% end %}

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}base{% end %}</title>
</head>
<body>
    {% block content %}
        base
    {% end %}
</body>
</html>

login.html

{% extends 'base.html' %}

{% block title %}
login page
{% end %}

{% block content %}

    <div class="">
        {% if error %}
            {{ error }}
        {% end %}
    <form action="/login?next={{ nextname }}" method="post" enctype="multipart/form-data">
        <div class="form-group">
            Username
            <input autofocus="" class="form-control" id="id_username" maxlength="254" name="username" type=