上一章我们讲到如何利用alembic来更新数据库,这章,我们讲如何通过七牛服务来存储图片。

  像我们大多数公司一样,公司资金比较少,如果自己开发图片服务器,代价太大;如果我们用自己的网站服务器来保存图片,很可能会把带宽阻塞住。因此,一款优秀的第三方图片服务变得非常重要。七牛就是这么一款,上传代码简单,可以在线编辑,简单的变换url,可以得到图片的不同效果。关键是,它是在一定限额内是免费的,只要通过认证,基本都够用了。我们公司现在包括app,网站所有图片都放在七牛,一直用的很好,一分钱也没有花。

  好了,闲话少说,自己先申请一个七牛账号,登录进去,可以自己先玩一下,直接上传一个图片。

  

  这就是我七牛账号里面的图片,我们点击内容上传,

速度不是一般的快呀,做技术出生的CEO果然就是不同,点击"关闭",然后打开外链,看看效果吧。http://7xk6rc.com1.z0.glb.clouddn.com/2016-05-04%2015-06-21%E5%B1%8F%E5%B9%95%E6%88%AA%E5%9B%BE.png 这是我刚才上传的,你可以打开看看,是不是很简单?就是这么简单,然后我们用编程的方式上传,仅此而已。

好了,下面上python上传代码,首先,按照文档,先安装一下qiniu模块。

pip install qiniu

安装好以后,先随便写一个python上传代码,看看我们实际过程中需要提供什么。

# coding:utf-8
from qiniu import Auth, put_file, etag, urlsafe_base64_encode access_key = 'access_key'
secret_key = 'secret_key' q = Auth(access_key=access_key, secret_key=secret_key) bucket_name = 'dameinv' key = 'my-test-picture.png' token = q.upload_token(bucket_name, key, 3600) print token localfile = './my-test.png' ret, info = put_file(token, key, localfile) print ret
print info

看看打印结果

hP7WNicFRHPu2Bd24MaLj5VvmElXYJbRCoZfrVs6:Fi7LRD1ufxI6GaoRRUeX9ncRk0g=:eyJzY29wZSI6ImRhbWVpbnY6bXktdGVzdC1waWN0dXJlLnBuZyIsImRlYWRsaW5lIjoxNDYyMzUwMTk3fQ==
{u'hash': u'FvSC6ud6RL3jLmARbabBuzQttbNO', u'key': u'my-test-picture.png'}
exception:None, status_code:, _ResponseInfo__response:<Response []>, text_body:{"hash":"FvSC6ud6RL3jLmARbabBuzQttbNO","key":"my-test-picture.png"}, req_id:pSEAAMKvVqF7TEsU, x_log:s.ph;s.put.tw;s.put.tr;s.put.tw;s.put.tr;s.ph;s.put.tw;s.put.tr;s.ph;PFDS;PFDS:;PFDS:;rs18_6.sel/not found;rdb.g/no such key;DBD/;v4.get:/Document not found;rs19_6.ups;qtbl.ups:;mc.s;RS:;rs.put:;rs-upload.putFile:;UP: Process finished with exit code

好了,看看实际在七牛的效果。

http://7xk6rc.com1.z0.glb.clouddn.com/my-test-picture.png

打开看看吧,这就是实际效果。

下面我们就来逐个分析一下代码,

首先,access_key和secret_key就是你的'个人面板'===>'密钥管理'里面的2个key,直接复制过来就可以了,这个key很重要,千万不能泄露哦。

其次,q = Auth(access_key=access_key, secret_key=secret_key)新建一个qiniu上传对象;bucket_name就是你的空间名,我的空间名是“dameimv”,可以建多个空间,看看我所有空间名;我用的最上面的那个;key,其实这个命名有点问题的,其实应该叫路径,至于为什么七牛文档中叫它key,就不得而知了;然后我们利用bucket_name和key,返回一个token,这个token以后就是我们主要返回给客户端的,第三个参数,就是它过期时间,我这边就随便设置1个小时过期。

最后,就是上传,其实以后,这是客户端的事,我们服务器端只要提供token和key就可以了,客户端上传成功以后,直接告诉我们路径即可。其实就是一个put_file而已。

看看返回结果,我个人就是看info的status_code,如果是200就代表上传成功。

是不是非常简单!好了,在此基础上,我们写接口吧。首先,我通常的做法是,服务器端提供token和key的接口,客户端拿到以后,自己上传图片,上传成功了,再把整个url给我,这样,服务器不会浪费任何带宽资源,而且也不会中途出错,导致其他问题。即使客户端出错,它可以自己重新上传,或者根本不上传,服务器端不需要存储任何数据,也不会出现其他意外。

import uuid
from qiniu import Auth, put_file, etag, urlsafe_base64_encode
access_key = 'access_key'
secret_key = 'secret_key'
q = Auth(access_key=access_key, secret_key=secret_key)
bucket_name = 'dameinv' @app.route('/get-qiniu-token')
def get_qiniu_token():
key = uuid.uuid4()
token = q.upload_token(bucket_name, key, 3600)
return jsonify({'code': 1, 'key': key, 'token': token}) @app.route('/set-head-picture', methods=['POST'])
@login_check
def set_head_picture():
head_picture = request.get_json().get('head_picture')
user = g.current_user
user.head_picture = head_picture
try:
db_session.commit()
except Exception as e:
print e
db_session.rollback()
return jsonify({'code': 0, 'message': '未能成功上传'})
redis_store.hset('user:%s' % user.phone_number, 'head_picture', head_picture)
return jsonify({'code': 1, 'message': '成功上传'})

我们在原来的view.py中添加如上代码,第一个get_qiniu_token是获取七牛的token和key,这边的key为了保持唯一,使用uuid,其实有2种方案,第一,你可以用这uuid,第二,你可以使用http://base_url/phone_number/time_stamp 这样的方式,其实我更倾向于第二种,这样,你就可以看到在这个用户下,有多少它上传的东西,便于直接统计。

整个上传代码就这样,照例,我们在client.py文件下,模拟一下客户端操作,看看有没有问题。

# coding:utf-8
import requests
import json
from qiniu import put_file class APITest(object):
def __init__(self, base_url):
self.base_url = base_url
self.headers = {}
self.token = None
self.qiniu_token = None
self.qiniu_key = None
self.qiniu_base_url = 'http://7xk6rc.com1.z0.glb.clouddn.com/' def login(self, phone_number, password, path='/login'):
payload = {'phone_number': phone_number, 'password': password}
self.headers = {'content-type': 'application/json'}
response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
response_data = json.loads(response.content)
self.token = response_data.get('token')
return response_data def user(self, path='/user'):
self.headers = {'token': self.token}
response = requests.get(url=self.base_url + path, headers=self.headers)
response_data = json.loads(response.content)
return response_data def logout(self, path='/logout'):
self.headers = {'token': self.token}
response = requests.get(url=self.base_url + path, headers=self.headers)
response_data = json.loads(response.content)
return response_data def get_qiniu_token(self, path='/get-qiniu-token'):
response = requests.get(url=self.base_url + path)
response_data = json.loads(response.content)
self.qiniu_token = response_data.get('token')
self.qiniu_key = response_data.get('key')
if self.qiniu_token and self.qiniu_key:
print '成功获取qiniu_token和qiniu_key,分别为%s和%s' % (self.qiniu_token.encode('utf-8'), self.qiniu_key.encode('utf-8'))
localfile = '/home/yudahai/PycharmProjects/blog01/app/my-test.png'
ret, info = put_file(self.qiniu_token, self.qiniu_key, localfile)
print info.status_code
if info.status_code == 200:
print '上传成功'
self.head_picture = self.qiniu_base_url + self.qiniu_key
print '其url为:' + self.head_picture.encode('utf-8')
else:
print '上传失败'
return response_data def set_head_picture(self, path='/set-head-picture'):
payload = {'head_picture': self.head_picture}
self.headers = {'token': self.token, 'content-type': 'application/json'}
response = requests.post(url=self.base_url + path, data=json.dumps(payload), headers=self.headers)
response_data = json.loads(response.content)
print response_data.get('message')
return response_data if __name__ == '__main__':
api = APITest('http://127.0.0.1:5001')
api.login('', '')
api.get_qiniu_token()
api.set_head_picture()
api.logout()

运行一下,看看结果吧。

 成功获取qiniu_token和qiniu_key,分别为hP7WNicFRHPu2Bd24MaLj5VvmElXYJbRCoZfrVs6:WZLWPx0bZ04KjSU0zRYKrPitWoE=:eyJzY29wZSI6ImRhbWVpbnY6YjU2NGJlOTAtMjM2ZS00YjQzLWE1M2UtZGRjMThlNTJmYmQxIiwiZGVhZGxpbmUiOjE0NjIzNTYwOTJ9和b564be90-236e-4b43-a53e-ddc18e52fbd1

 上传成功
其url为:http://7xk6rc.com1.z0.glb.clouddn.com/b564be90-236e-4b43-a53e-ddc18e52fbd1
成功上传

已经上传成功了,看看头像结果

>>> from app.model import *
>>> user = User.query.filter_by('').first()
Traceback (most recent call last):
File "<input>", line , in <module>
TypeError: filter_by() takes exactly argument ( given)
>>> user = User.query.filter_by(phone_number='').first()
>>> user.head_picture
u'http://7xk6rc.com1.z0.glb.clouddn.com/b564be90-236e-4b43-a53e-ddc18e52fbd1'

看,已经成功了。

以后几乎所有的图片都可以这么处理,在客户端需要图片之前,让他们先访问get-qiniu-token接口,拿到token和key,客户端根据token和key来上传自己的东西。每上传一次,就访问一次get-qiniu-token接口。

好了,这就是简单的七牛上传图片介绍,详细的说明,他们都有文档,文档做的非常清晰。下一章,我们利用容联云通讯来完成注册过程,也非常简单。

flask开发restful api系列(4)--七牛图片服务的更多相关文章

  1. flask开发restful api系列(8)-再谈项目结构

    上一章,我们讲到,怎么用蓝图建造一个好的项目,今天我们继续深入.上一章中,我们所有的接口都写在view.py中,如果几十个,还稍微好管理一点,假如上百个,上千个,怎么找?所有接口堆在一起就显得杂乱无章 ...

  2. flask开发restful api系列(1)

    在此之前,向大家说明的是,我们整个框架用的是flask + sqlalchemy + redis.如果没有开发过web,还是先去学习一下,这边只是介绍如果从开发web转换到开发移动端.如果flask还 ...

  3. flask开发restful api系列(7)-蓝图与项目结构

    如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restful api的最明显效果就是版本控制:而 ...

  4. flask开发restful api系列(6)-配置文件

    任何一个好的程序,配置文件必不可少,而且非常重要.配置文件里存储了连接数据库,redis的用户密码,不允许有任何闪失.要有灵活性,用户可以自己配置:生产环境和开发环境要分开,最好能简单的修改一个东西, ...

  5. flask开发restful api系列(3)--利用alembic进行数据库更改

    上面两章,主要讲基本的配置,今天我们来做一个比较有趣的东西,为每个客户加一个头像图片.如果我们图片保存在自己的服务器,对于服务器要求有点高,每次下载的时候,都会阻塞网络接口,要是1000个人同时访问这 ...

  6. flask开发restful api系列(5)-短信验证码

    我们现在开发app,注册用户的时候,不再像web一样,发送到个人邮箱了,毕竟个人邮箱在移动端填写验证都很麻烦,一般都采用短信验证码的方式.今天我们就讲讲这方面的内容. 首先,先找一个平台吧.我们公司找 ...

  7. flask开发restful api系列(2)

    继续上一章所讲,上一章我们最后面说道,虽然这个是很小的程序,但还有好几个要优化的地方.先复制一下老的view.py代码. # coding:utf-8 from flask import Flask, ...

  8. flask开发restful api

    flask开发restful api 如果有几个原因可以让你爱上flask这个极其灵活的库,我想蓝图绝对应该算上一个,部署蓝图以后,你会发现整个程序结构非常清晰,模块之间相互不影响.蓝图对restfu ...

  9. 描述怎样通过flask+redis+sqlalchemy等工具,开发restful api

    flask开发restful api系列(8)-再谈项目结构 摘要: 进一步介绍flask的项目结构,使整个项目结构一目了然.阅读全文 posted @ 2016-06-06 13:54 月儿弯弯02 ...

随机推荐

  1. Android自定义View 构造方法 遇到的一些问题

    Android开发中,经常会自定义View,那么就会使用构造方法,比如自定义MyView,继承View,会要求实现构造方法: public MyView(Context context) { supe ...

  2. 转:对于linux下system()函数的深度理解(整理)

    这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...

  3. swipejs

    http://swipejs.com/ http://www.scoop.it/t/javascript-for-mobile http://www.open-open.com/news/view/c ...

  4. POJ 2135 Farm Tour

    题目大意:有一个无向图..农夫从1号点出发..要到达N号点..然后回到1号点..来回不能走相同的路径..问最短的距离是多少. 题解:又是不能走重复路径!基本图论算法直接扔掉上网络流.不能相同就边限1, ...

  5. 黑马程序员_Java泛型

    泛型 概述: ClassCaseException:类型转换异常. 代码中不加泛型,编译没问题,运行可能会发生异常.但是用户解决不了,这样程序就存在安全隐患.所以我们希望在编译时期就能看出问题,程序员 ...

  6. Java---设计模块(单例的变形)(多例)

    设计模式1--单例变形(多例) ★ 缓存在单例中的使用 缓存在编程中使用很频繁,有着非常重要的作用,它能够帮助程序实现以空间换取时间,通常被设计成整个应用程序所共享的一个空间,现要求实现一个用缓存存放 ...

  7. HDU_2016——数据的交换输出

    Problem Description 输入n(n<100)个数,找出其中最小的数,将它与最前面的数交换后输出这些数.   Input 输入数据有多组,每组占一行,每行的开始是一个整数n,表示这 ...

  8. Linux 常用命令记录

    1.查看磁盘空间使用情况 df -[a i m] 或更多 df -lh 2.查看目录文件占用大小 du -sh * du --max-depth=1 -lh 3.内存使用qingkuang free ...

  9. ReactJS 的背景及原理

    原文链接:http://www.infoq.com/cn/articles/subversion-front-end-ui-development-framework-react 在Web开发中,我们 ...

  10. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...