【问题标题】:Flask - Calling python function that return image on button OnClickFlask - 调用在按钮 OnClick 上返回图像的 python 函数
【发布时间】:2019-12-17 09:12:01
【问题描述】:

我正在尝试制作一个非常简单的 Web 应用程序,它获取客户端输入的图像,然后在服务器上对其进行处理,然后返回图像。我希望图像显示在其中一个 div 上。我尝试使用ajax,但它不起作用。 我对烧瓶和ajax很陌生,找到了返回文本的例子。

这是我的 ma​​in.py

import os
#import magic
import urllib.request
from app import app
from flask import Flask, flash, request, redirect, render_template, send_file
from werkzeug.utils import secure_filename
from fungsi import plot

ALLOWED_EXTENSIONS = set(['txt', 'tif'])

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def upload_form():
    return render_template('upload_.html')

@app.route('/', methods=['POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the files part
        if 'files[]' not in request.files:
            flash('No file part')
            return redirect(request.url)
        files = request.files.getlist('files[]')
        for file in files:
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        flash('Files successfully uploaded')
        return redirect('/')

@app.route('/foo', methods=['GET'])
def foo():
    for root, dirs, files in os.walk(app.config['UPLOAD_FOLDER']):
        for file in files:
            if file.endswith('B4.TIF'):
                fname4 = os.path.join(app.config['UPLOAD_FOLDER'], file)
            if file.endswith('B5.TIF'):
                fname5 = os.path.join(app.config['UPLOAD_FOLDER'], file)

    bytes_obj = plot(fname4,fname5)

    return send_file(bytes_obj,
                     attachment_filename='plot.png',
                     mimetype='image/png')

if __name__ == "__main__":
    app.run()

html代码

<!doctype html>
<html>
<title>Python Flask Multiple Files Upload Example</title>

<head><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> </head>


<body>

    <div class="row">
        <div class="col-sm-6">
            <h4>Plot</h4>
            <button id='myButton' type="button">Click Me!</button>
            <div id="img"></div>
        <div class="col-sm-6">
            <h2>Select file(s) to upload</h2>
            <p>
                {% with messages = get_flashed_messages() %}
                  {% if messages %}
                    <ul class=flashes>
                    {% for message in messages %}
                      <li>{{ message }}</li>
                    {% endfor %}
                    </ul>
                  {% endif %}
                {% endwith %}
            </p>
            <form method="post" action="/" enctype="multipart/form-data">
                <dl>
                    <p>
                        <input type="file" name="files[]" multiple="true" autocomplete="off" required>
                    </p>
                </dl>
                <p>
                    <input type="submit" value="Submit">
                </p>
            </form>
        </div>
    </div>

</body>
<script>
                $(document).ready(function() {
                $('#myButton').click(function() {
                    $.ajax({
                          type:"get",
                          url: "/foo",
                          dataType:"image/png"
                          success: function(response){
                           $("#img").html(response.html);
                          }
                  });
                });
                });
            </script>
</html>

【问题讨论】:

  • 我认为最简单的方法是将图像保存为具有特定(动态生成)名称的文件,将名称传递给 HTML,然后像 &lt;img src="static/images/{{ processed_image_name }}" /&gt; 一样渲染它。
  • @Ardweaden 实际上在我尝试使用 ajax 之前,我使用此代码 ``
    `` ,但是当我第一次加载html页面那里有一个图像标志,然后在我提交数据输入后,处理后的图像出现在那里。让我感到困惑的是,我认为徽标有点破损,因为处理代码无法找到输入数据,因为客户端尚未上传它,这是否意味着实际上处理代码自页面访问以来已经运行?我希望在上传图像然后单击处理按钮后运行处理功能。
  • 当然,图像在您保存之前没有定义,因此它显示了损坏图像的徽标。如果未定义名称,您可以将 {% if processed_image_name %}&lt;img src="static/images/{{ processed_image_name }}" /&gt;{% endif %} 作为图像元素不显示图像。
  • 顺便说一句,我建议您为每个图像使用唯一的名称,否则其他用户将相互覆盖。您可以像这样将名称传递给模板:stackoverflow.com/questions/17057191/…
  • @Ardweaden 如果我选择不保存图像并使用发送文件,我可以应用这样的东西吗?
  • 标签: javascript python jquery ajax flask


    【解决方案1】:

    您首先需要运行才能制作烧瓶形式

    pip install flask-wtf
    

    一旦你这样做了,制作一个像这样的表单文件:

    from flask_wtf import FlaskForm
    from flask_wtf.file import SubmitField
    
    class foo(FlaskForm):
        image=FileField('Images')
        submit=SubmitField('Submit')
    

    然后在您的路线文件中。我还没有找到一种方法来绕过使用 if 语句来确保列表已填充,但老实说,我还没有真正尝试过并且它有效。它将返回一个对象列表,并确保第一个的文件名不是空字符串(表示实际上没有选择图像),然后它应该可以工作。 python 文件应如下所示。

    from formFile import foo
    
    @app.route('/whatever',methods=['POST'])
    def bar():
        form=foo()
        images=[]
        if form.image.data[0].filename!='':
            images.append(image)
        return render_template('yourHTML.html',form=form,images=images)
    

    我只是添加了额外的导入,并没有添加所有相关的导入。现在要访问每个图像,您只需要运行一个简单的 for 循环

    for image in form.image.data:
        //for loop contents
    

    您的 html 文件的表单部分与此类似:

    <form method="POST" action="" enctype="multipart/form-data">
        {{form.hidden_tag()}}
        <fieldset class="form">
            <legend class="legend">Upload Image</legend>
                <div class="scrolling-wrapper">
                    <p class="form-control-label">Current Images</p>
                    {%for image in images%}
                        <div class="card"><img src="/static/images/{{image}}" alt="Pic"/></div>
                    {%endfor%}
                </div>
            <div class="form-group">
                {{ form.image.label() }}
                {{ form.image(class="form-control-file") }}
                {% if form.image.errors %}
                    {% for error in form.image.errors %}
                        <span class="text-danger">{{ error }}</span></br>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="form-group">
                {{form.submit(class="btn btn-outline-info")}}
            </div>
        </fieldset>
    </form>
    

    您不需要错误部分。这里使用的类是 Bootstrap 的一部分,只是为了样式,所以很明显,如果您愿意,可以用自己的样式替换它们。 “滚动包装”类是一个自定义类,只是为了将所有图片放在可滚动框中的一行中。我可以添加你想要的代码。这应该是您需要的一切,如果我遗漏了任何内容,可能是因为我使用了自己的代码,该代码实现了将图片保存到服务器的保存功能,并且可以通过 SQL 数据库查询访问特定的图像。如果我不得不猜测你可以使用:src={{image}} 而不是src="/static/images/products/{{image}}",但不要强迫我,因为我没有测试过。另外我没有添加任何验证器,但无论如何你都知道如何实现它们。

    【讨论】:

      猜你喜欢
      • 2017-07-24
      • 2021-09-20
      • 2020-08-17
      • 2015-09-03
      • 2018-06-27
      • 2015-05-14
      • 2015-06-20
      • 1970-01-01
      相关资源
      最近更新 更多