7 增加图片喜欢信息

增加功能

增加用户页面

  • /profile handler

class ProfileHandler(AuthBaseHandler):
	"""
	显示用户上传的图片 和 喜欢的图片列表
	"""

	@tornado.web.authenticated
	def get(self, *args, **kwargs):
		user = get_user(self.current_user)
		like_post_list = get_like_post(user)
		self.render('profile.html', user=user, like_post_list=like_post_list)

.card卡片组件(样式)

  • html 模板
{% extends 'base.html' %}

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

{% block content %}
    <div class="row">
        <div class="card col-12">
            <div class="card-header"><h3>{{ current_user }}用户上传</h3></div>
            {% for post in user.posts %}
                <div class="col-6 col-sm-3">
                    <a href="/post/{{ post.id }}">
                        <img src="{{ static_url(post.thumb_url) }}">
                    </a>
                </div>
            {% end %}
        </div>
        <div class="card col-12">
            <div class="card-header"><h3>用户喜欢</h3></div>
            {% for post in like_post_list %}
                <a href="/post/{{ post.id }}">
                    <img src="{{ static_url(post.thumb_url) }}">
                </a>
            {% end%}
         </div>
    </div>
{% end %}


记录用户喜欢的图片

  • 增加 Like model (记录哪个用户 喜欢 哪个图片)
  class Like(Base):
     """
     记录用户喜欢的图片信息
     """
     __tablename__ = 'likes'
     user_id = Column(Integer, ForeignKey('users.id'), nullable=False, primary_key=True)
     post_id = Column(Integer, ForeignKey('posts.id'), nullable=False, primary_key=True)
alembic revision --autogenerate -m 'add like model'

alembic upgrade head
  • 数据库操作

    • 用户喜欢的哪些图片
    • 一个图片有哪些用户喜欢
  • 增加辅助函数

utils/account

  def get_user(username):
  	"""
  	查询用户user
  	:return: 
  	"""
  	user = session.query(Users).filter_by(name=username).first()
  	return user
  
  
  def get_like_post(user):
     """
     查询用户user喜欢的图片的post对象
     :param user:  Users的实例
     :return:  Posts的实例
     """
     # posts = []
     # likes = session.query(Like).filter_by(user_id=user.id).all()
     # for like in likes:
     #  post = session.query(Posts).filter_by(id=like.post_id).first()
     #  posts.append(post)
     posts = session.query(Posts).filter(Like.user_id == user.id, Posts.id == Like.post_id).all()
     return posts
  • like 操作 ajax post

展示在用户和单独图片页面

  • 读取数据到 handler
  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:
           like_count = get_like_count(post)
           self.render('post.html', post=post, like_count=like_count)
  • 修改 html 模板
    post.html
{% extends 'base.html' %}

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

{% block content %}

    <div class="row">
        <div class="col-sm-8">
            <img src="{{ static_url(post.image_url)}}" width="560">
        </div>
        <div class="col-sm-4">
            upload by {{ post.user.name }}<br>
            {% if like_count %}
                <i class="fa fa-heart text-danger"></i> {{ like_count }}
            {% end %}
        </div>
    </div>
{% end %}

作业

增加用户页面和 likes 表,展示图片的喜欢信息

代码

app.py

import tornado.web
import tornado.options
import tornado.ioloop
from tornado.options import define, options

from handlers import main,auth

define(name='port', default='8000', type=int, help='run port')


class Application(tornado.web.Application):
   def __init__(self):
      handlers = [
         (r'/', main.IndexHandler),
         (r'/explore', main.ExploreHandler),
         (r'/post/(?P<post_id>[0-9]+)', main.PostHandler),
         (r'/upload', main.UploadHandler),
         (r'/profile', main.ProfileHandler),
         (r'/login', auth.LoginHandler),
         (r'/logout', auth.LogoutHandler),
         (r'/signup', auth.SignupHandler),
      ]
      settings = dict(
         debug=True,
         template_path='templates',
         static_path='static',
         login_url='/login',
         cookie_secret='bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=',
         pycket={
            'engine': 'redis',
            'storage': {
               'host': 'localhost',
               'port': 6379,
               # 'password': '',
               'db_sessions': 5,  # redis db index
               'db_notifications': 11,
               'max_connections': 2 ** 30,
            },
            'cookies': {
               'expires_days': 30,
            },
         }
      )

      super(Application, self).__init__(handlers, **settings)


application = Application()

if __name__ == '__main__':
   tornado.options.parse_command_line()
   application.listen(options.port)
   print("Server start on port {}".format(str(options.port)))
   tornado.ioloop.IOLoop.current().start()

utils/account.py

import hashlib
from models.account import Users, session, Posts, Like
from datetime import datetime
from sqlalchemy import func


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


def get_user(username):
	"""
	查询用户user
	:return:
	"""
	user = session.query(Users).filter_by(name=username).first()
	return user


def get_like_post(user):
	"""
	查询用户user喜欢的图片的post对象
	:param user:  Users的实例
	:return:  Posts的实例
	"""
	# posts = []
	# likes = session.query(Like).filter_by(user_id=user.id).all()
	# for like in likes:
	# 	post = session.query(Posts).filter_by(id=like.post_id).first()
	# 	posts.append(post)

	# 去除用户自己上传的图片
	posts = session.query(Posts).filter(Like.user_id == user.id, Posts.id == Like.post_id,
										Posts.user_id != user.id).all()
	return posts


def get_like_count(post):
	"""

	:param post:
	:return:
	"""
	like_count = session.query(Like).filter_by(post_id=post.id).count()
	return like_count

models/account.py

from sqlalchemy import (Column, Integer, String, DateTime, ForeignKey)
from sqlalchemy import exists
from sqlalchemy.orm import relationship
from sqlalchemy.sql import exists

from .db import Base, DBSession

from datetime import datetime

session = DBSession()


class Users(Base):
	__tablename__ = 'users'

	id = Column(Integer, primary_key=True, autoincrement=True)
	name = Column(String(50), unique=True, nullable=False)
	password = Column(String(50), nullable=False)
	created = Column(DateTime, default=datetime.now)
	email = Column(String(50))
	last_login = Column(DateTime)

	def __repr__(self):
		return '<User(#{}:{})>'.format(self.id, self.name)

	# 增加用户到数据库中
	@classmethod
	def add_user(cls, username, password, email=''):
		user = Users(name=username, password=password, email=email, last_login=datetime.now())
		session.add(user)
		session.commit()

	# 查询用户username对应的密码
	@classmethod
	def get_passwd(cls, username):
		user = session.query(Users).filter_by(name=username).first()
		# 如果用户存在 返回密码
		if user:
			return user.password
		# 用户不存在 返回空
		else:
			return ''

	# 判断用户是否存在于数据库中
	@classmethod
	def is_exists(cls, username):
		ret = session.query(exists().where(Users.name == username)).scalar()
		return ret


class Posts(Base):
	"""
	用户图片信息
	"""
	__tablename__ = 'posts'
	id = Column(Integer, primary_key=True, autoincrement=True)
	image_url = Column(String(100))  # 大图路径
	thumb_url = Column(String(100))  # 缩略图路径
	user_id = Column(Integer, ForeignKey('users.id'))
	# Post 有user属性 存放Users对象 , Users有posts属性 存放Posts对象
	user = relationship('Users', backref='posts', uselist=False, cascade='all')

	# 保存用户上传的图片信息  图片和特定的用户建立关系(这张图片是由这个用户传上来的)
	@classmethod
	def add_post_for(cls, username, image_url, thumb_url):
		user = session.query(Users).filter_by(name=username).first()
		post = Posts(image_url=image_url, thumb_url=thumb_url, user=user)
		session.add(post)
		session.commit()
		return post


class Like(Base):
	"""
	记录用户喜欢的图片信息
	"""
	__tablename__ = 'likes'
	user_id = Column(Integer, ForeignKey('users.id'), nullable=False, primary_key=True)
	post_id = Column(Integer, ForeignKey('posts.id'), nullable=False, primary_key=True)


if __name__ == '__main__':
	Base.metadata.create_all()

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, get_user, get_like_post, get_like_count
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:
			like_count = get_like_count(post)
			self.render('post.html', post=post, like_count=like_count)


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'})


class ProfileHandler(AuthBaseHandler):
	"""
	显示用户上传的图片 和 喜欢的图片列表
	"""

	@tornado.web.authenticated
	def get(self, *args, **kwargs):
		username = self.get_argument('name', None)  # url传参
		print(username)
		if not username:  # name=空
			username = self.current_user
		user = get_user(username)
		if user:
			like_post_list = get_like_post(user)
			self.render('profile.html', user=user, like_post_list=like_post_list)
		else:
			self.render('error.html')

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="{{ static_url('css/bootstrap.css') }}">
    <link rel="stylesheet" href="{{ static_url('font-awesome-4.7.0/css/font-awesome.css') }}">
    <title>{% block title %}base{% end %}</title>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">
            <i class="fa fa-camera"></i>
            Tudo 图片
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="/">首页<span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/explore">发现</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        用户中心
                    </a>
                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                      <a class="dropdown-item" href="/profile">个人信息</a>
                      <a class="dropdown-item" href="#">收藏</a>
                      <div class="dropdown-divider"></div>
                      <a class="dropdown-item" href="#">Something else here</a>
                    </div>
                </li>
                <li class="nav-item">
                    <a class="nav-link disabled" href="/logout">{{ current_user }}登出</a>
                </li>
            </ul>
            <a class="btn btn-info" href="/upload">
                <i class="fa fa-upload"></i>
                上传
            </a>
        </div>
    </nav>

    <div class="container">
        {% block content %}
            base
        {% end %}
    </div>
    <script src="{{ static_url('js/jquery-3.3.1.slim.min.js') }}"></script>
    <script src="{{ static_url('js/popper.min.js') }}"></script>
    <script src="{{ static_url('js/bootstrap.js') }}"></script>
</body>
</html>


profile.html

{% extends 'base.html' %}

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

{% block content %}
    <div class="card">
       <div class="card-header"><h3>{{ user.name }}用户上传</h3></div>
        <div class="row">
            {% for post in user.posts %}
                <div class="col-6 col-sm-3">
                    <a href="/post/{{ post.id }}">
                        <img src="{{ static_url(post.thumb_url) }}" class="img-fluid">
                    </a>
                </div>
            {% end %}
        </div>
    </div>
    <div class="card">
        <div class="card-header"><h3>用户喜欢</h3></div>
        <div class="row">
            {% for post in like_post_list %}
                <div class="col-6 col-sm-3">
                    <a href="/post/{{ post.id }}">
                        <img src="{{ static_url(post.thumb_url) }}" class="img-fluid">
                    </a>
                </div>
        {% end%}
        </div>
    </div>
{% end %}



post.html

{% extends 'base.html' %}

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

{% block content %}

    <div class="row">
        <div class="col-sm-8">
            <img src="{{ static_url(post.image_url)}}" width="560">
        </div>
        <div class="col-sm-4">
            upload by {{ post.user.name }}<br>
            {% if like_count %}
                <i class="fa fa-heart text-danger"></i> {{ like_count }}
            {% end %}
        </div>
    </div>
{% end %}

error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <img src="{{ static_url('images/error.jpg') }}">
    <h3>您访问的页面不存在</h3>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值