upload files using flask-uploads
Asked Answered
H

3

6

I am trying to upload files using the flask-uploads extension. The problem is that, each time it seems I find a solution, I fund an other problem, and I feel the documentation cryptic.

Here is the code :

from flask.ext.uploads import UploadSet, IMAGES, configure_uploads 
import os
from werkzeug import secure_filename

photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)

@app.route('/edit_book', methods = ['GET', 'POST'])
def edit_book():
form = BookForm()
if form.validate_on_submit():
            b.summary = form.summary.data
    if request.method == 'POST':
        try:
            secure_filename = photos.save(request.files['cover'])
        except:
            print 'not ok'
            db.session.add(b)
    db.session.commit()
    return redirect('/admin')
return render_template('edit_book.html', title = 'Add a book', form = form )

The current error give just :

KeyError: 'images'.

I have nothing more ! Does any one issue in using this extension, as I find no suitable piece of code anywhere that give a full solution (from the start of an upload to the saving of the file in a folder).

Thank you in advance for your help.

Template code

<!-- extend from admin layout -->
{% extends "admin.html" %}

{% block content %}
 <form action="" method="post" name="edit_book" enctype="multipart/form-data">
{{form.hidden_tag()}}

{% if dico %}
 <h1>Ajouter le livre <i>{{dico.title}}</i> à la base de données</h1>
{% else %}
{% set dico = [] %}
 <h1>Ajouter un livre à la base de données</h1>
 {% endif %}
<p>Titre (obligatoire) :    {{form.title(value=dico.title)}}</p>
<p>ISBN 13 (EAN) :      {{form.ean(value=dico.EAN)}}</p>
<p>ISBN :           {{form.isbn(value=dico.ISBN)}}</p>
<p>Maison d'édition :       {{form.publisher(value=dico.publisher)}}</p>
<p>epaisseur (cm) :     {{form.thickness(value=dico.thickness)}}</p>
<p>longueur (cm) :      {{form.length(value=dico.length)}}</p>
<p>largeur (cm) :       {{form.width(value=dico.width)}}</p>
<p>masse (kg) :         {{form.mass(value=dico.mass)}}</p>
<p>Nombre de pages :        {{form.numberofpages(value=dico.pages)}}</p>
<p>Couverture du livre :    {{form.cover(value=dico.img)}}</p>
<p>Quatrième de couverture :    {{form.summary(cols="35", rows="20")|safe}}</p>
<p><input type="submit" value="Envoyez"></p>
</form>
{% endblock %}

Error Stacktrace

* Running on http://127.0.0.1:5000/
* Restarting with reloader
127.0.0.1 - - [22/Jul/2013 15:16:18] "POST /edit_book HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1360, in    full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1358, in  full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1344, in  dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/stephane/git/biblib-flask/app/views.py", line 117, in edit_book
if form.validate_on_submit():
File "/usr/local/lib/python2.7/dist-packages/flask_wtf/form.py", line 125, in  validate_on_submit
return self.is_submitted() and self.validate()
 File "/usr/local/lib/python2.7/dist-packages/wtforms/form.py", line 265, in validate
return super(Form, self).validate(extra)
 File "/usr/local/lib/python2.7/dist-packages/wtforms/form.py", line 130, in validate
if not field.validate(self, extra):
 File "/usr/local/lib/python2.7/dist-packages/wtforms/fields/core.py", line 176, in  validate
 stop_validation = self._run_validation_chain(form, chain)
 File "/usr/local/lib/python2.7/dist-packages/wtforms/fields/core.py", line 196, in _run_validation_chain
 validator(form, self)
 File "/usr/local/lib/python2.7/dist-packages/flask_wtf/file.py", line 69, in __call__
if not self.upload_set.file_allowed(field.data, field.data.filename):
 File "/usr/local/lib/python2.7/dist-packages/Flask_Uploads-0.1.3-    py2.7.egg/flaskext/uploads.py", line 346, in file_allowed
 return self.extension_allowed(extension(basename))
 File "/usr/local/lib/python2.7/dist-packages/Flask_Uploads-0.1.3-py2.7.egg/flaskext/uploads.py", line 356, in extension_allowed
 return ((ext in self.config.allow) or
 File "/usr/local/lib/python2.7/dist-packages/Flask_Uploads-0.1.3-py2.7.egg/flaskext/uploads.py", line 308, in config
 return current_app.upload_set_config[self.name]
 KeyError: 'images'
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?    __debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?__debugger__=yes&cmd=resource&f=ubuntu.ttf HTTP/1.1" 200 -
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
 127.0.0.1 - - [22/Jul/2013 15:16:18] "GET /edit_book?__debugger__=yes&cmd=resource&f=source.png HTTP/1.1" 200 -

I just checked the code more largely, and find only one thing that is exactly 'images' : a validator in the forms.

 from flaskext.uploads import UploadSet, IMAGES
 images = UploadSet("images", IMAGES)

 class BookForm(Form):
    summary = TextAreaField('summary', [validators.optional()])
cover = FileField("cover", [validators.optional(),file_allowed(images, "Images only!")])
Haemophilia answered 22/7, 2013 at 13:1 Comment(11)
Can you share the full stack trace please?Monochromatism
You can find what you want down. I hope it will help you, cause it doesn't help me !Haemophilia
Please don't add non-answers to answer section. You can edit the question and put the log below in the question itself if it is relevant.Coley
Can you please delete the stack trace from the answer section? I have added it to your question.Acquit
Does your template contain a 'name="images"' form field?Tympanitis
the template contains a 'cover' field which corresponds to the file I upload named cover in the code.Haemophilia
I suggest you post the template code as well.Acquit
By using the photos and covers UploadSet intsead of 'images', this doesn't crash any more, but still doesn't upload anything. I get one step further, but not to the end !Haemophilia
It is difficult to tell what's going on here. Where are you saving the images? Are you sure you don't have any typos or mistakes in configuration of the url where uploads are going to be stored?Panhandle
It is supposed to save the covers in '/covers'. I know the file are sent, because a 'if 'cover' in request.files' ask answer well.Haemophilia
It succeed ! I don't know really how, but it succeed !Haemophilia
A
2

The problem is, you have two upload set: one for views.py (photos), one for forms.py(images). You should import the upload set photos from your app.py.

Besides, Flask-Uploads will call secure_filename() to verify filename for you, so this line is unnecessary:

from werkzeug import secure_filename

A complete demo is here:

import os
from flask import Flask, render_template
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed
from wtforms import SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'I have a dream'
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd()

photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app)  # set maximum file size, default is 16MB


class UploadForm(FlaskForm):
    photo = FileField(validators=[FileAllowed(photos, u'Image only!'), FileRequired(u'File was empty!')])
    submit = SubmitField(u'Upload')


@app.route('/', methods=['GET', 'POST'])
def upload_file():
    form = UploadForm()
    if form.validate_on_submit():
        filename = photos.save(form.photo.data)
        file_url = photos.url(filename)
    else:
        file_url = None
    return render_template('index.html', form=form, file_url=file_url)


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

template:

<h1>Photo Upload</h1>
<form method="POST" enctype="multipart/form-data">
    {{ form.hidden_tag() }}
    {{ form.photo }}
    {% for error in form.photo.errors %}
        <span style="color: red;">{{ error }}</span>
    {% endfor %}
    {{ form.submit }}
</form>

{% if file_url %}
<br>
<img src="{{ file_url }}">
{% endif %}

Gist Link: https://gist.github.com/greyli/81d7e5ae6c9baf7f6cdfbf64e8a7c037

Auditor answered 18/1, 2017 at 4:54 Comment(0)
B
1

I was running into the same problem.

The problem is that in your configuration you configure the following UploadSet

photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)

But the form field cover uses the following UploadSet

images = UploadSet("images", IMAGES)

You just need to import the photos UploadSet and change the cover field to:

cover = FileField("cover", [validators.optional(),file_allowed(photos, "Images only!")])

This did the trick for me.

Barring answered 19/10, 2015 at 23:48 Comment(0)
C
0

photos = ['png','jpeg','gif'] # extension of file you want to validate cover = FileField("cover", validators=[FileRequired(), FileAllowed(photos, 'Message')])

This will do the tricks ;)

Cromlech answered 17/3, 2020 at 21:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.