【问题标题】:What is the correct way to serve/access media files in Flask在 Flask 中提供/访问媒体文件的正确方法是什么
【发布时间】:2021-10-28 23:59:31
【问题描述】:

我正在努力解决以下问题:在 Flask 中提供媒体文件的正确方法是什么?我在博客系统中建立了一个模型Posts,我正在使用flask-file-upload

# models/blog.py
from app import db, file_upload

@file_upload.Model
class Posts(db.Model):
    """
    Defines the attributes of posts table in the database
    """
    ...
    image = file_upload.Column()
    ...

在我的settings.py 文件中

import os
from pathlib import Path

PROJECT_ROOT = Path(__file__).parent.parent
UPLOAD_FOLDER = os.path.join(PROJECT_ROOT, 'media')

所以,当我添加 Post 对象时,它会将文件名保存在数据库中,并将文件保存在媒体文件夹中,路径为 media/posts/<post_id>/filename

到目前为止,它运行良好。但我需要提供这些图片,所以我创建了以下路线:

# routes.py

from app import app

@app.get('/media/<path:path>')
def send_media(path):
    """
    :param path: a path like "posts/<int:post_id>/<filename>"
    :return:
    """
    path_list = path.split('/')
    path_ = '/'.join(path_list[:-1]) + '/'
    file_name = path_list[-1]
    return send_from_directory(
        directory=app.config['UPLOAD_FOLDER'], path=path_, filename=file_name, as_attachment=True
    )

但是当我浏览http://127.0.0.1:5000/media/posts/15/python.jpg时它不起作用

我的 Flask 应用程序响应 404 - Not Found,即使 python.jpg 文件在那里。

如何正确访问 Flask 中的媒体文件? 我需要这个,因为我必须创建一个发送 file_name 的 API,并且前端将呈现图像,类似于

<img src="http://localhost:8000/media/posts/<post_id>/file_name">

【问题讨论】:

    标签: python flask


    【解决方案1】:

    在我看来,flask-file-upload 扩展基本上使用了一个upload_folder,它位于静态文件夹中。如果指定了不同的位置,上传也可以工作,但 get_file_url 函数不会返回正确的位置。此外,需要一个单独的下载路径,因为您要在此处创建。

    如果您指定一个文件夹(如文档中所示,该文件夹位于静态文件夹内),您的工作会更轻松。

    否则,这是我的示例,用于不同的位置。这不是最好的方法,但它确实有效。

    import os
    from flask import Flask
    from flask import render_template, request, send_from_directory
    from flask_sqlalchemy import SQLAlchemy
    from flask_file_upload.file_upload import FileUpload
    
    
    app = Flask(__name__)
    app.config['UPLOAD_FOLDER'] = os.path.join(app.root_path, 'media')
    app.config['ALLOWED_EXTENSIONS'] = ['jpg', 'png']
    app.config['MAX_CONTENT_LENGTH'] = 1000 * 1024 * 1024  # 1000mb
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.sqlite'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    
    db = SQLAlchemy(app)
    file_upload = FileUpload(app, db)
    
    @file_upload.Model
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        image = file_upload.Column()
    
        @property
        def image_url(self):
            return f'{self.__tablename__}/{self.id}/{self.image__file_name}'
    
    with app.app_context():
        db.drop_all()
        db.create_all()
    
    @app.route('/create', methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            my_img = request.files['my-img']
            post = Post()
            file_upload.save_files(post, files={ 'image': my_img })
            db.session.add(post)
            db.session.commit()
        posts = Post.query.all()
        return render_template('create.html', **locals())
    
    @app.route('/media/<path:filename>')
    def media(filename):
        return send_from_directory(
            app.config['UPLOAD_FOLDER'],
            filename,
            as_attachment=True
        )
    
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title></title>
      </head>
      <body>
        <form method="post" enctype="multipart/form-data">
          <input type="file" name="my-img" />
          <input type="submit" />
        </form>
    
        <div>
          {% for post in posts %}
            <div><a href="{{ url_for('media', filename=post.image_url) }}">{{post.image__file_name}}</a></div>
          {% endfor %}
        </div>
    
      </body>
    </html>
    

    【讨论】:

    • 谢谢@Detlef 可能你所做的工作,但我的问题是我将参数传递给 send_from_directory() 函数的方式。
    【解决方案2】:

    解决方案:看到 send_from_directory() 文档字符串我明白了!我们不需要path_listpath_file_name 变量。使用 Flask 提供媒体文件的正确方法是:

    @app.get('/media/<path:path>')
    def send_media(path):
        """
        :param path: a path like "posts/<int:post_id>/<filename>"
        """
    
        return send_from_directory(
            directory=app.config['UPLOAD_FOLDER'], path=path
        )
    

    【讨论】:

      猜你喜欢
      • 2021-03-02
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 2013-05-03
      • 2015-12-08
      • 2013-03-27
      相关资源
      最近更新 更多