Flask — wtforms: Проверка не выполняется с помощью валидатора `FileRequired ()`, даже если формы нет.ошибки

#python #html #flask #flask-wtforms #csrf-token

Вопрос:

Я новичок в Колбе. Я много читал, но не мог найти решения.

Когда я комментирую валидаторы FileField ( pic ), код работает просто отлично. С валидаторами — нет form.errors , но все равно form.validate_on_submit() ложно.

Редактировать:

  • Если я использую только FileAllowed валидатор, то form.validate_on_submit() это верно, даже если тип файла не «png»…
  • Если я использую только FileRequired() валидатор, form.validate_on_submit() это ложь.

Это важная часть main.py:

 import os
from flask import Flask, render_template, request, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_wtf.csrf import CSRFProtect,CSRFError

#from werkzeug.utils import secure_filename

app = Flask(__name__)

# Flask-WTF requires an encryption key - the string can be anything
app.config['SECRET_KEY'] = 'nydtnvbkadjshnvcksdnvcld'

app._static_folder = 'D:/a/b/c/static'
#app.config['UPLOAD_FOLDER'] = 'D:/a/b/c/uploads/'
app.debug = True

# Flask-Bootstrap requires this line
Bootstrap(app)

ANALYSIS_FOLDER = 'D:/a/b/c/analysis/'

##########################  test  ###########################################
class NameForm(FlaskForm):
    name = StringField('Which actor is your favorite?', validators=[DataRequired()])
    pic = FileField('Picture of actor:',
                    validators=[FileRequired(), FileAllowed(['png'], 'png files only!')]
                    )
    submit = SubmitField('Submit')

@app.route('/test', methods=['GET', 'POST'])
def test():
    form = NameForm(request.form)
    print(form.errors)
    print(form.validate_on_submit())

    if form.validate_on_submit():
        print('Hello')
        # create a folder for the new dataset
        new_n = dataset_number(ANALYSIS_FOLDER)
        data_path = os.path.join(ANALYSIS_FOLDER, 'data'   str(new_n))
        print(data_path)
        os.mkdir(data_path)

        # save name
        with open(os.path.join(data_path, 'name_of_actor.txt'), 'w') as text_file:
            text_file.write(form.name.data)

        uploaded_file = request.files['pic']
        print(uploaded_file)
        if uploaded_file:
            print(uploaded_file.filename)
            uploaded_file.save(os.path.join(data_path, 'file.png'),)

        return redirect(url_for('home'))
        #return f'''<h1> {form.name.data} is a great actor! </h1>'''
    return render_template('test.html', form=form)
 

Это base.html:

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
    <style>
        .formdesign {
          background-color: #BFC9CA;
          color: black;
          margin: 10px;
          padding: 5px;
        }
    </style>
    {% block head %} {% endblock %}
</head>
<body style="background-color:#BFC9CA">
    {% block body %} {% endblock %}
</body>
</html>
 

и это test.html:

 {% extends 'base.html' %}

{% block head %}
<title>Test</title>
{% endblock %}

{% block body %}
<h1>Test!</h1>
<form method="POST" action="" enctype="multipart/form-data">
    {{ form.csrf_token() }}
    <div class="form-row">
        <div class="form-group col-md-6">
            {{ form.csrf_token() }}
            <label for=""> {{ form.name.label }}</label>
            {{ form.name }}
            <p> Names are super important. </p>
        </div>
        <hr>
        <div class="form-group col-md-6">
            {{ form.csrf_token() }}
            <label for=""> {{ form.pic.label }}</label>
            {{ form.pic }}
            <p> Pictures are also super important. </p>
        </div>
        <div class="form-group">
            {{ form.csrf_token() }}
            {{ form.submit(class="btn btn-primary")}}
        </div>
    </div>
</form>
{% endblock %}
 

Ответ №1:

В полях указаны ошибки WTForms. Если вы хотите получить к нему доступ, вам необходимо использовать form.pic.errors

Проверьте документацию, например: https://flask-wtf.readthedocs.io/en/0.15.x/quickstart/#validating-forms

Комментарии:

1. form.pic.errors также пусто — ошибок нет.

2. Что, если вы сделаете form = NameForm() это вместо form = NameForm(request.form) этого ? (как в официальной документации). Кроме того, старайтесь попадать form.pic.errors только после form.validate_on_submit()

Ответ №2:

Я решил эту проблему с помощью загрузки колб.

Мое main.py сейчас выглядит так:

 import os
from flask import Flask, render_template, request, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_uploads import UploadSet, configure_uploads, patch_request_class, IMAGES

ANALYSIS_FOLDER = 'D:/a/b/c/analysis/'

app = Flask(__name__)

# Flask-WTF requires an encryption key - the string can be anything
app.config['SECRET_KEY'] = 'nydtnvbkadjshnvcksdnvcld'
app.config['UPLOADED_PHOTOS_DEST'] = ANALYSIS_FOLDER

app._static_folder = 'D:/a/b/c/static'
app.debug = True

# Flask-Bootstrap requires this line
Bootstrap(app)

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

##########################  test   ###########################################
class NameForm(FlaskForm):
    name = StringField('Which actor is your favorite?', validators=[DataRequired()])
    pic = FileField('Picture of actor:',
                    validators=[FileRequired(), FileAllowed(photos, 'images only!')]
                    )
    submit = SubmitField('Submit')

@app.route('/test', methods=['GET', 'POST'])
def test():
    form = NameForm(request.form)

    #if form.validate_on_submit():
    if request.method == 'POST' and 'pic' in request.files:
        print('Hello')

        new_n = dataset_number(ANALYSIS_FOLDER)
        data_path = os.path.join(ANALYSIS_FOLDER, 'data'   str(new_n))
        print(data_path)
        os.mkdir(data_path)

        # save e-mail
        with open(os.path.join(data_path, 'name_of_actor.txt'), 'w') as text_file:
            text_file.write(form.name.data)

        filename = photos.save(storage=request.files['pic'], folder='data'   str(new_n), name='pic.')
        print(filename)

        return redirect(url_for('home'))
    return render_template('test.html', form=form)
 

И test.html :

 {% extends 'base.html' %}

{% block head %}
<title>Test</title>
{% endblock %}

{% block body %}
<h1>Test!</h1>
<form method="POST" action="{{ url_for('test') }}" enctype="multipart/form-data">
    {{ form.csrf_token() }}
    <div class="form-row">
        <div class="form-group col-md-6">
            {{ form.csrf_token() }}
            <label for=""> {{ form.name.label }}</label>
            {{ form.name }}
            <p> Names are super important. </p>
        </div>
        <hr>
        <div class="form-group col-md-6">
            {{ form.csrf_token() }}
            <label for=""> {{ form.pic.label }}</label>
            {{ form.pic }}
            <p> Pictures are also super important. </p>
        </div>
        <hr>
        <div class="form-group">
            {{ form.csrf_token() }}
            {{ form.submit(class="btn btn-primary")}}
        </div>
    </div>
</form>
{% endblock %}