2016-09-04 29 views
12

Mam problem z pobieraniem pliku do pracy w aplikacji cookiecutter-flask (wersja 0.10.1). W tej chwili nie zapisuje przesłanego pliku.Plik nie jest przesyłany za pomocą Flask-wtforms w aplikacji kolba kucharska

Cookiecutter-Flask domyślnie instaluje WTForms i Flask-WTForms. Próbowałem dodać do tego Flask-Uploads, ale nie jestem przekonany, że moduł dodaje coś w tym momencie, więc odinstalowałem go. To jest dokumentacja ładowania pliku Flask-WTF: http://flask-wtf.readthedocs.io/en/latest/form.html#module-flask_wtf.file

Główna różnica między dokumentacją a moją aplikacją polega na tym, że wydaje mi się, że mam więcej informacji w większej liczbie plików, zgodnie z konwencjami dotyczącymi gotowości.

W app_name/spreadsheet/forms.py:

from flask_wtf import Form 
from wtforms.validators import DataRequired 
from flask_wtf.file import FileField, FileAllowed, FileRequired 

class UploadForm(Form): 
    """Upload form.""" 

    csv = FileField('Your CSV', validators=[FileRequired(),FileAllowed(['csv', 'CSVs only!'])]) 

    def __init__(self, *args, **kwargs): 
     """Create instance.""" 
     super(UploadForm, self).__init__(*args, **kwargs) 
     self.user = None 

    def validate(self): 
     """Validate the form.""" 
     initial_validation = super(UploadForm, self).validate() 
     if not initial_validation: 
      return False 

W app_name/spreadsheet/views.py:

from flask import Blueprint, render_template 
from flask_login import login_required 
from werkzeug.utils import secure_filename 
from app_name.spreadsheet.forms import UploadForm 
from app_name.spreadsheet.models import Spreadsheet 
from app_name.utils import flash, flash_errors 

blueprint = Blueprint('spreadsheet', __name__, url_prefix='/spreadsheets', static_folder='../static') 

@blueprint.route('/upload', methods=['GET', 'POST']) #TODO test without GET since it won't work anyway 
@login_required 
def upload(): 
    uploadform = UploadForm() 
    if uploadform.validate_on_submit(): 
     filename = secure_filename(form.csv.data.filename) 
     uploadform.csv.data.save('uploads/csvs/' + filename) 
     flash("CSV saved.") 
     return redirect(url_for('list')) 
    else: 
     filename = None 
    return render_template('spreadsheets/upload.html', uploadform=uploadform) 

To wyjście linii poleceń pokazuje żadnych błędów, kiedy załadować plik:

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 
127.0.0.1 - - [04/Sep/2016 10:29:10] "GET /spreadsheets/upload HTTP/1.1" 200 - 
127.0.0.1 - - [04/Sep/2016 10:29:10] "GET /_debug_toolbar/static/css/toolbar.css?0.3058158586562558 HTTP/1.1" 200 - 
127.0.0.1 - - [04/Sep/2016 10:29:14] "POST /spreadsheets/upload HTTP/1.1" 200 - 
127.0.0.1 - - [04/Sep/2016 10:29:14] "GET /_debug_toolbar/static/css/toolbar.css?0.3790246965220061 HTTP/1.1" 200 - 

dla katalogu uploads/csvs Próbowałem ścieżki bezwzględne i względne i Katalog jest permissioned 766.

Plik szablonu jest:

{% extends "layout.html" %} 
{% block content %} 
    <h1>Welcome {{ session.username }}</h1> 

    {% with uploadform=uploadform %} 
     {% if current_user and current_user.is_authenticated and uploadform %} 
      <form id="uploadForm" method="POST" class="" action="{{ url_for('spreadsheet.upload') }}" enctype="multipart/form-data"> 
       <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> 
       <div class="form-group"> 
       {{ uploadform.csv(class_="form-control") }} 
       </div> 
       <button type="submit" class="btn btn-default">Upload</button> 
      </form> 
     {% endif %} 
    {% endwith %} 

{% endblock %} 

który generuje ten HTML:

 <form id="uploadForm" method="POST" class="" action="/spreadsheets/upload" enctype="multipart/form-data"> 
      <input type="hidden" name="csrf_token" value="LONG_RANDOM_VALUE"/> 
      <div class="form-group"> 
      <input class="form-control" id="csv" name="csv" type="file"> 
      </div> 
      <button type="submit" class="btn btn-default">Upload</button> 
     </form> 

Odpowiedz

0

pominie dokumentacji, link podałeś wskazuje, że pole jest csvdata instancja o numerze werkzeug.datastructures.FileStorage. Dokumentacja dla FileStorage.save() sugeruje, że:

Jeśli miejscem docelowym jest obiekt pliku, musisz zamknąć go sam po zakończeniu połączenia.

Czy to możliwe, ponieważ nie zamykasz pliku, nie jest on zapisywany na dysku?

0

Spróbuj tego:

from flask import request 

if uploadform.validate_on_submit(): 
    if 'csv' in request.files: 
     csv = request.files['csv'] 
     csv.save('uploads/csvs/' + csv.filename) 
0

główną przyczyną Twojego problemu ziem tutaj:

def validate(self): 
    """Validate the form.""" 
    initial_validation = super(UploadForm, self).validate() 
    if not initial_validation: 
     return False 

więc w validate metoda UploadForm klasę.

Zobaczmy, co się tutaj dzieje.

W views.py w linii:

if uploadform.validate_on_submit(): 

flask_wtf pakiet nazywa validate metody.Więc spójrz jeszcze raz na swoją nadpisaną metodę:

def validate(self): 
    """Validate the form.""" 
    initial_validation = super(UploadForm, self).validate() 
    if not initial_validation: 
     return False 

co jest nie tak? W przypadku, gdy initial_validation będzie True, twoja metoda validate zwróci None. Co więc powinno się stać? Tylko renderowania HTML:

def upload(): 
    uploadform = UploadForm() 
    if uploadform.validate_on_submit(): # <--- here it's None 
     filename = secure_filename(form.csv.data.filename) 
     uploadform.csv.data.save('uploads/csvs/' + filename) 
     flash("CSV saved.") 
     return redirect(url_for('list')) 
    else:        # <--- so this block runs 
     filename = None 
    # And your app will only render the same view as when using HTTP GET on that method 
    return render_template('spreadsheets/upload.html', uploadform=uploadform) 

Więc jeśli nadpisywania validate metoda nie jest konieczne, a potem po prostu usunąć go, a jeśli jest, to dostosowanie go do powrotu True:

def validate(self): 
    """Validate the form.""" 
    initial_validation = super(UploadForm, self).validate() 
    if not initial_validation: 
     return False 
    return True # <-- this part is missing 

Oczywiście można użyć skrócone i Myślę, że bardziej odpowiednia wersja:

def validate(self): 
    """Validate the form.""" 
    initial_validation = super(UploadForm, self).validate() 
    return not initial_validation