I made a flask_wtf Form with this field:
logo_image = FileField('logo_image', validators=[FileRequired(), FileAllowed(['jpg', 'png'], 'Images only!')])
My form looks like this:
<form action="" method="POST" name="app_branding" enctype="multipart/form-data">
{{ form.csrf_token }}
{{ form.brand.label }} {{ form.brand }}
{{ form.logo_image.label }} {{ form.logo_image }}
{{ form.title_text.label }} {{ form.title_text }}
{{ form.first_paragraph.label }} {{ form.first_paragraph }}
{{ form.faq.label }} {{ form.faq }}
{{ form.privacy_policy.label }} {{ form.privacy_policy }}
{{ form.success_message.label }} {{ form.success_message }}
{{ form.submit.label }} {{ form.submit }}
</form>
For debugging, in my view, I put:
#expose('/', methods=['GET', 'POST'])
def index(self):
form = BrandForm(request.form)
print(form.validate())
print(form.errors)
print("request.files")
print(request.files)
And in the console I get the message that logo_image is required, even though it is there in request.files:
False
{'logo_image': ['This field is required.']}
request.files
ImmutableMultiDict([('logo_image', <FileStorage: u'20140725_095232.jpg' ('image/jpeg')>)])
How do I get the FileRequired() method to detect the file?
request.form only contains form input data. request.files contains file upload data. You need to pass the combination of both to the form. Since your form inherits from Flask-WTF's Form (now called FlaskForm), it will handle this automatically if you don't pass anything to the form.
form = BrandForm()
if form.validate_on_submit():
...
Without Flask-WTF, use a CombinedMultiDict to combine the data and pass that to the form.
from werkzeug.datastructures import CombinedMultiDict
form = BrandForm(CombinedMultiDict((request.files, request.form)))
if request.method == 'POST' and form.validate():
...
Related
I am writing an application on Flask, I made authorization on flask-login, but an error appears during authorization itself. I use also Flask-WTF.
I have the simplest form of Flask WTF:
class LoginForm(FlaskForm):
email = StringField("Email: ", validators=[Email()])
password = PasswordField("Password: ", validators=[DataRequired(), Length(min=4, max=100)])
submit = SubmitField("Войти")
There is an HTML form:
<form action="/accounting" method="POST">
{{ form.csrf_token }}
{{ form.email.label() }} {{ form.email() }}
{{ form.password.label() }} {{ form.password() }}
{{ form.submit() }}
</form>
I tried to specify the HTML form {{ form.hidden_tag() }}
There is also a function:
#app.route('/login', methods=['POST', 'GET'])
def login():
if current_user.is_authenticated:
return redirect('/accounting')
form = LoginForm()
if form.validate_on_submit():
email = request.form['email']
user = UserModel.query.filter_by(email=email).first()
if user is not None and user.check_password(request.form['password']):
login_user(user)
return redirect('/accounting')
return render_template('login.html', form=form)
I couldn't find an answer on the Internet that fits my case, so I'm asking here.
Why does an error appear when submitting the form?
Bad Request
The CSRF session token is missing.
After rendering, the token is present:
<input id="csrf_token" name="csrf_token" type="hidden" value="IjhlMDBjMDhmYTIwOGUyNGQ5OGNiMTY0ZGZhOTU3Njc0ZDJhNjY4MDgi.YSW1_g.fhKQUYljjLKqUtl0OdcuOgJx02U">
I tried it both ways:
app.config['SECRET_KEY'] = SECRET_KEY
app.secret_key = "ff82b98ef8727e388ea8bff063"
There are also such lines:
csrf = CSRFProtect(app)
csrf.init_app(app)
Your error is in the html template. remove the action and add the hidden tags
<form method="POST">
{{ form.hidden_tag() }}
{{ form.email.label() }} {{ form.email() }}
{{ form.password.label() }} {{ form.password() }}
{{ form.submit() }}
</form>
Jinja Template Code
<form method="POST">
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
</form>
Form Class
class NameForm(FlaskForm):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
pdb> request.form
ImmutableMultiDict([('name', 'rohit'), ('submit', 'Submit')])
form.validate_on_submit() is returning False instead of True.
Fr the above to work you also need to add protection against cross-site referencing in the HTML code. Adding this line
{{ form.hidden_tag() }}
might solve the problem.
I have been trying to implement a way to post a project post where the user can upload multiple images. The multiple image upload works but posting the post itself does not work.
I am not sure what to do with the project_form.
It is not valid even tho the fields have correct values.
My code is:
views.py
class CreateProjectsView(View):
def get(self, request):
p_photos = P_Images.objects.all()
#project_form = ProjectsForm(initial=self.initial)
project_form = ProjectsForm
context = {
'p_photos': p_photos,
'project_form': project_form,
}
return render(self.request, 'projects/forms.html', context)
def post(self, request):
project_form = ProjectsForm(request.POST or None, request.FILES or None)
p_formset = P_ImageForm(request.POST, request.FILES)
# Checks if the project_form is valid before save
if project_form.is_valid():
instance = project_form.save(commit=False)
instance.user = request.user
instance.save()
# Checks if multiple image upload is valid before save
if p_formset.is_valid():
#if project_form.is_valid() and p_formset.is_valid():
#instance = project_form.save(commit=False)
#instance.user = request.user
#instance.save()
images = p_formset.save(commit=False)
images.save()
data = {
'is_valid': True,
'name': images.p_file.name,
'url': images.p_file.url
}
else:
data = {
'is_valid': False,
}
return JsonResponse(data)
forms.html
<form action="{% url 'create_post:retrieve_projects' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in project_form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in project_form %}
{{ field.errors }}
{{ field }} <br />
{% endfor %}
<input type="submit" value="OK">
</form>
If the form is not valid, you should provide a way for the user to correct their errors and resubmit the form. Perhaps something like this:
if project_form.is_valid():
instance = project_form.save(commit=False)
instance.user = request.user
instance.save()
else:
return render(request, 'project_form.html', {'form': project_form})
So I actually found a fix for this.
The issue is in the forms.html
I changed the "create_post:retrieve_projects" to "create_post:create_projects" in my form section.
forms.html
<form action="{% url 'create_post:create_projects' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in project_form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in project_form %}
{{ field.errors }}
{{ field }} <br />
{% endfor %}
<input type="submit" value="OK">
</form>
I made a flask_wtf Form with this field:
logo_image = FileField('logo_image', validators=[FileRequired(), FileAllowed(['jpg', 'png'], 'Images only!')])
My form looks like this:
<form action="" method="POST" name="app_branding" enctype="multipart/form-data">
{{ form.csrf_token }}
{{ form.brand.label }} {{ form.brand }}
{{ form.logo_image.label }} {{ form.logo_image }}
{{ form.title_text.label }} {{ form.title_text }}
{{ form.first_paragraph.label }} {{ form.first_paragraph }}
{{ form.faq.label }} {{ form.faq }}
{{ form.privacy_policy.label }} {{ form.privacy_policy }}
{{ form.success_message.label }} {{ form.success_message }}
{{ form.submit.label }} {{ form.submit }}
</form>
For debugging, in my view, I put:
#expose('/', methods=['GET', 'POST'])
def index(self):
form = BrandForm(request.form)
print(form.validate())
print(form.errors)
print("request.files")
print(request.files)
And in the console I get the message that logo_image is required, even though it is there in request.files:
False
{'logo_image': ['This field is required.']}
request.files
ImmutableMultiDict([('logo_image', <FileStorage: u'20140725_095232.jpg' ('image/jpeg')>)])
How do I get the FileRequired() method to detect the file?
request.form only contains form input data. request.files contains file upload data. You need to pass the combination of both to the form. Since your form inherits from Flask-WTF's Form (now called FlaskForm), it will handle this automatically if you don't pass anything to the form.
form = BrandForm()
if form.validate_on_submit():
...
Without Flask-WTF, use a CombinedMultiDict to combine the data and pass that to the form.
from werkzeug.datastructures import CombinedMultiDict
form = BrandForm(CombinedMultiDict((request.files, request.form)))
if request.method == 'POST' and form.validate():
...
Trying my first app in Django, and have some problem on form validation (following documentation)
This is part of file upload code. The form creates fine. But, the validation fails.
Even though, I provide Title, it gives This field is required.
views.py
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
#TODO handle(request.FILES['file'])
return HttpResponseRedirect('/')
else:
form = UploadFileForm()
return render_to_response('setup.html', {'form': form},context_instance=RequestContext(request))
forms.py
from django import forms
class UploadFileForm(forms.Form):
title = forms.CharField()
file = forms.FileField()
setup.html
<form action="/setup/" method="post">{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<input type="submit" value="Submit" />
</form>
Add required paremeter to your form field. If you don't provide it Django will assume it is required.
title = forms.CharField(required=False)