配置项
为了方便的图片的保存与展示,可以在 配置文件中,指明 图片资源的路径
1 import os 2 3 4 class Config(object): 5 DEBUG = True 6 SQLALCHEMY_DATABASE_URI = 'mysql://root:mysql@127.0.0.1:3306/day08' 7 SQLALCHEMY_TRACK_MODIFICATIONS = False 8 9 # 构建项目所在的 绝对路径,也就是 day08 的绝对路径 10 BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 11 # 自己指明的 图片上传路径 12 MEDIA_ROOT = os.path.join(BASE_DIR, 'MEDIA/')
模型类
1 from app.extensions import db 2 from datetime import datetime 3 4 5 # 分类: id、name 6 class Cate(db.Model): 7 __tablename__ = 'tb_cate' 8 id = db.Column(db.Integer, primary_key=True, autoincrement=True) 9 name = db.Column(db.String(32), unique=True, nullable=False) 10 11 12 # 新闻: id、title、content、count、img、time、cate_id 13 class News(db.Model): 14 __tablename__ = 'tb_news' 15 id = db.Column(db.Integer, primary_key=True, autoincrement=True) 16 title = db.Column(db.String(32), unique=True, nullable=False) 17 content = db.Column(db.Text) 18 count = db.Column(db.Integer, default=0) 19 img = db.Column(db.String(256)) # 图片字段中,存放的是 图片地址,并不是图片本身 20 time = db.Column(db.DateTime, default=datetime.now) 21 cate_id = db.Column(db.Integer, db.ForeignKey('tb_cate.id')) 22 # 关系 23 cate = db.relationship('Cate', backref='news')
工具集
自定义函数,将图片保存到本地
1 import os 2 from uuid import uuid4 3 from flask import current_app # current_app 属于应用上下文,代表项目中的app本身 4 5 6 def img_upload(img): 7 if not img: 8 return None 9 10 # 将图片名按照 . 进行切分, 找到最后一个元素,也就是 文件的后缀名 11 end_name = img.filename.rsplit('.')[-1] 12 13 # 通过文件的后缀名判断 身份为 合法的 图片 14 if end_name not in ['jpg', 'png', 'gif', 'jpeg']: 15 return None 16 17 # 将 图片对象 存入 本地,然后将 路径 存入 数据库 18 MEDIA = current_app.config['MEDIA_ROOT'] # 从app的配置项,取出 MEDIA的路径 19 filename = str(uuid4()) + '.' + end_name # 为了生成一个不重复的 文件名 20 img_path = os.path.join(MEDIA, filename) # 将路径和文件名拼接在一起,方便保存文件 21 22 img.save(img_path) # 将图片对象保存到 本地 23 24 return filename
视图
图片上传
上传图片的逻辑, 和一般的 添加数据流程一样,只是多了一步: 将图片对象保存到本地
1 class NewsView(Resource): 2 def post(self): 3 # 1. 创建解析参数的对象 4 parser = reqparse.RequestParser() 5 # 2. 指明需要解析的参数 6 parser.add_argument('title', type=str, location='form', required=True) 7 parser.add_argument('content', type=str, location='form') 8 parser.add_argument('count', type=int, location='form', default=0) 9 parser.add_argument('cate_id', type=int, location='form', required=True) 10 parser.add_argument('img', type=FileStorage, location='files') 11 12 # 3. 获取具体的参数 13 args = parser.parse_args() 14 15 title = args.get('title') 16 content = args.get('content') 17 count = args.get('count') 18 cate_id = args.get('cate_id') 19 img = args.get('img') 20 21 # 利用自定义函数,将图片保存到本地 22 filename = img_upload(img) 23 24 # 4. 创建对象, 注意:图片存储的只是 从media之后的 图片路径 25 news = News(title=title, content=content, count=count, img=filename, cate_id=cate_id) 26 # 5. 添加到 事务中 27 db.session.add(news) 28 # 6. 提交事务 29 try: 30 db.session.commit() 31 except: 32 return { 33 'msg': '添加失败' 34 }, 500 35 # 7. 返回响应 36 return { 37 'id': news.id, 38 'title': news.title, 39 'img': news.img 40 }, 201
图片展示
图片展示,实际就是 将 图片内容读取为文件流,做为响应返回
http://127.0.0.1:5000/media/filename
1 class ImgView(Resource): 2 def get(self, filename): 3 # 1. 从配置项中读取 media目录的 路径 4 MEDIA = current_app.config['MEDIA_ROOT'] 5 # 2. 拼接除图片的完成路径 6 img_path = os.path.join(MEDIA, filename) 7 8 # 3. 按照二进制方式打开文件,读到的内容为 二进制文件流,方便接下来的网络传输 9 try: 10 with open(img_path, 'rb') as f: 11 img = f.read() 12 except FileNotFoundError: 13 return None, 404 14 15 # 4. 自定义响应 16 resp = make_response(img) 17 # 5. 声明响应体的类型 为 图片 18 resp.headers['Content-Type'] = 'image/png' 19 # 6. 返回响应 20 return resp
1 # 路由匹配,获取文件名 2 3 api.add_resource(ImgView, '/media/<string:filename>')