【问题标题】:How to display ImageGridFSProxy in HTML?如何在 HTML 中显示 ImageGridFSProxy?
【发布时间】:2015-03-31 09:09:13
【问题描述】:

我在 MongoDB 中存储了几张图像,现在我想在网页中显示它们。我正在为我的应用程序使用 Flask。该记录有一个名为“payload”的二进制字段

class BinaryFile(mongo.Document):
    created_at = mongo.DateTimeField(default=datetime.datetime.now, required=True)
    file_name = mongo.StringField(max_length=255, required=True)
    payload = mongo.ImageField(required=False)

我想显示有效载荷。关于如何做到这一点的任何线索?我试过了

<img src="{{ image.payload }}"/>

这只是给了我一个断开的链接。然后页面的源代码为

<img src="&lt;ImageGridFsProxy: None&gt;"/>

如果我尝试

<img src="{{ image.payload.read() }}"/>

我明白了

UnicodeDecodeError: 'ascii' codec can't decode byte 0x89 in position 0: ordinal not in range(128)

有点难过。有任何想法吗?谢谢!

【问题讨论】:

    标签: html mongodb flask pymongo gridfs


    【解决方案1】:

    image.payload.read() 返回图像的原始数据,这是我们想要的,只是我们不想把它放在 IMG 标签的 src 属性中。

    我们想要的是将原始图像数据作为图像提供,并将该图像的 URL 放入 src 属性。

    Here is one example how it can be done with a temporary file. 这很可能是您想要的解决方案。

    from tempfile import NamedTemporaryFile
    from shutil import copyfileobj
    
    tempFileObj = NamedTemporaryFile(mode='w+b',suffix='jpg')
    copyfileobj(image.payload,tempFileObj)
    tempFileObj.seek(0,0)
    

    然后在视图中提供文件

    from flask import send_file
    
    @app.route('/path')
    def view_method():
        response = send_file(tempFileObj, as_attachment=False, attachment_filename='myfile.jpg')
        return response
    

    可能直接从 ImageGridFSProxy 对象发送图像数据并跳过临时文件,但我不确定。

    ---------

    现在您已经完成了代码,我将按照我的方式发布。以及我试图解释的方式。 :)

    这是我的 app.py。

    from flask import Flask, send_file, render_template
    import mongoengine as mo
    
    app = Flask(__name__)
    c = mo.connection.connect('localhost')
    
    @app.route('/')
    def index():
        images = MyDoc.objects.all()
        return render_template('template.html', images=images)
    
    # Separate view for the images
    @app.route('/image/<img_name>')
    def image(img_name):
        image = MyDoc.objects(file_name=img_name).first()
        # This is where the tempfile stuff would have been if it would
        # have been needed.
        if image:
            return send_file(image.payload, mimetype='image')
        else:
            return "404" # might want to return something real here too
    
    class MyDoc(mo.Document):
        file_name = mo.StringField(max_length=255, required=True)
        payload = mo.ImageField(required=True)
    
    if __name__ == "__main__":
        app.run(debug=True)
    

    这是模板。

    <html>
    <body>
    <div>
        This is a body!
        <div>
            {% if images %}
               {% for image in images %}
                 {{ image.file_name }}
                 <img src="/image/{{ image.file_name }}" />
                 I'm an image!<br><br>
               {% endfor %}
            {% endif %}
    
        </div>
    </div>
    </body>
    </html>
    

    整个tempfile 是不必要的,因为可以直接使用send_file 发送有效负载。需要 mimetype 来告诉浏览器“这是一个图像”,并且浏览器应该只显示它​​而不是下载它。这不是我之前怀疑的as_attachment

    这样就无需使用tempfile 保存文件或将文件保存到静态提供它们的目录中。

    【讨论】:

    • 谢谢,我试试看。保存临时文件感觉效率低下。另外,我想渲染图像,看起来 send_file 方法将其附加为下载。最后,你可以这样处理多个文件吗?感谢您的帮助!
    • 啊,可能是as_attachment=True 是它开始下载它的原因。将其切换为False,它应该可以工作。
    • 您可以使用它来处理多个文件,方法是为图像提供一些 ID,并通过以下方式在视图中引用它们:@app.route('/image/&lt;int:image_id&gt;'),然后使用 ID 获取正确的图像。
    • 如果我没记错的话,Mongo 已经为文档提供了 ID。你可以使用这些。
    • 我一直在玩这个,今天下午会更新。非常感谢您的帮助!
    【解决方案2】:

    非常感谢@sevanteri 让我开始。为了后代,这就是我最终做的事情

    观点:

    @app.route('/index')
    def index():
        images = BinaryFile.objects.all()
        for image in images:
            # This was the temp file idea, abandoned...
            # tmpImageFile = NamedTemporaryFile(mode="w+b", suffix="jpg", delete=False, dir="app/static/temporary_files")
            # copyfileobj(image.payload,tmpImageFile)
            # tmpImageFile.seek(0,0)
            with open(app.config['TEMPORARY_FILE_DIR'] + "/" + image.file_name, 'wb') as f:
                f.write(image.payload.read())
            # image.temporary_file_location = app.config['TEMPORARY_FILE_DIR'] + "/" + image.file_name
            image.temporary_file_location = "static/tmp/" + image.file_name
    
    
        return render_template('dashboard.html', images=images)
    

    html:

    {% block content %}
    <div>
        This is a body!
        <div>
            {% if images %}
               {% for image in images %}
                 {{ image.file_name }}
                 <img src="{{ image.temporary_file_location }}"/>
                 I'm an image!<br><br>
               {% endfor %}
            {% endif %}
    
        </div>
    </div>
    
    {% endblock %}
    

    型号:

    import datetime
    from app import mongo
    from flask import url_for
    
    class BinaryFile(mongo.Document):
        created_at = mongo.DateTimeField(default=datetime.datetime.now, required=True)
        file_name = mongo.StringField(max_length=255, required=True)
        payload = mongo.ImageField(required=False)
    
        def get_absolute_url(self):
            return url_for('post', kwargs={"binary_file": self.file_name})
    
        def __unicode__(self):
            return self.title
    

    所以这有点糟糕,因为我使用的是复制命令。它满足了我在 mongo 中保存图像然后显示它们的 POC,我会让我的工程师弄清楚实际文件的管理。他们比我聪明。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-24
      • 2011-08-31
      • 2011-01-08
      • 2019-01-25
      • 2014-06-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多