HTML form ignores file section - python

When I submit my form, by analyzing request I saw that every field is submitted except file data and I don't know why. I would really be happy if anybody could give me a hint how to solve this problem.
my route.py file
#users.route("/account", methods=["GET", "POST"])
#login_required
def account():
form = UpdateAccountForm()
if form.validate_on_submit():
if form.pic.data:
file_data = save_pict(form.pic.data)
current_user.picture = file_data
else:
print("no data was sent")
current_user.username = form.username.data
current_user.email = form.email.data
db.session.commit()
flash("Your profile was updated!", "success")
return redirect(url_for("users.account"))
forms file
class UpdateAccountForm(FlaskForm):
username = StringField("Username", validators=[DataRequired(), Length(min=5, max=15)])
email = StringField("Email", validators=[DataRequired(), Email()])
pic = FileField("Update Picture", validators=[FileAllowed(["jpeg", "png"])])
submit = SubmitField("Update")
HTML file
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src={{image}}>
<br>
<div class="media-body">
<br>
<h2 class="account-heading">{{current_user.username}}</h2>
<p class="secondary">{{current_user.email}}</p>
</div>
</div>
<div class="registration-form">
<form method="post" action="" enctype="multipart/form-data">
{{form.hidden_tag()}}
<fieldset class="form-group"><br>
<legend class="border-bottom mb-4">Account info</legend>
<div class="form-group">
{{form.username.label(class="form-control-label")}}
{%if form.username.errors%}
{{form.username(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{%for error in form.username.errors%}
<span>{{error}}</span>
{%endfor%}
</div>
{%else%}
{{form.username(class="form-control form-control-lg")}}
{%endif%}
</div>
<div class="form-group">
{{form.email.label(class="form-control-label")}}
{%if form.email.errors%}
{{form.email(class="form-control form-control-lg is-invalid")}}
<div class="invalid-feedback">
{%for error in form.email.errors%}
<span>{{error}}</span>
{%endfor%}
</div>
{%else%}
{{form.email(class="form-control form-control-lg")}}
{%endif%}
</div>
<div class="form-group">
{{ form.pic.label() }}
{{ form.pic(class="form-control-file") }}
{% if form.pic.errors %}
{% for error in form.pic.errors %}
<span class="text-danger">{{ error }}</span></br>
{% endfor %}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{form.submit(class="btn btn-outline-info")}}
</div>
</form>
</div>
</div>
So when I inspect body of the request every field is present except file field, and nothing is submitted to database
request body photo

Related

Why the html custom form is not working django

I have a contact page with a simple form.
Here is views.py:
def contact_view(request):
if request.method == 'GET':
form = ContactForm()
else:
form = ContactForm(request.POST)
if form.is_valid():
subject = form.cleaned_data['subject']
from_email = form.cleaned_data['from_email']
message = form.cleaned_data['message']
try:
send_mail(subject, message, from_email, settings.ADMIN_EMAILS)
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('success')
return render(request, "base/contact.html", {'form': form})
def success_view(request):
return HttpResponse('Success! Thank you for your message.')
this is contact.html:
{% block content%}
<main class="page contact-page">
<section class="portfolio-block contact">
<div class="container">
<div class="heading">
<h2>Contact me</h2>
</div>
<form method="post">
{% csrf_token %}
<div class="mb-3"><label class="form-label" for="name">Your Name</label><input class="form-control item" type="text" id="name"></div>
<div class="mb-3"><label class="form-label" for="subject">Subject</label><input class="form-control item" type="text" id="subject"></div>
<div class="mb-3"><label class="form-label" for="email">Email</label><input class="form-control item" type="email" id="email"></div>
<div class="mb-3"><label class="form-label" for="message">Message</label><textarea class="form-control item" id="message"></textarea></div>
<div class="mb-3"><button class="btn btn-primary btn-lg d-block w-100" type="submit" value="submit">Submit Form</button></div>
</form>
</div>
</section>
</main>
{% endblock %}
When I use form.as_p it works very well but when I use this template it is not working
it only shows in the terminal that a post request was made.
The html looping syntax of form is following, where we have access to specific field, field.label ,non_field_errors as well as particular field errors.
In your case you can use in this way:
contact.html
{% block content%}
<main class="page contact-page">
<section class="portfolio-block contact">
<div class="container">
<div class="heading">
<h2>Contact me</h2>
</div>
<form method="POST" novalidate>
{% csrf_token %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<div>
{{error}}
</div>
{% endfor %}
{% endif %}
{% for field in form %}
<p>{{field.label_tag}} {{field}}</p>
<br>
{% for error in field.errors %}
<span>{{error}}</span>
{% endfor %}
{% endfor %}
<input type="submit" value="Save">
</form>
</div>
</section>
</main>
{% endblock %}
You can use it as above it will work perfectly with your existing views, as you said it is working with form.as_p.
If you give only form.as_p, it will render form fields in <p> tag of html, you can see through Ctrl+U of view page source,there we cannot have more control over form.
Your question -- How can i use bootstrap's classes in django's form?
Answer - You can set through widget in your form's fileds. for example:
class MyForm(forms.Form):
name=forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
In the above way, you can set it to every field.

flask wtforms showing validation error on 2 forms on the same html page and same route/view

So I have 2 forms, login form and registration form, on home.html, which show up as a modal when clicked on the login button, which looks like as follows:
home.html
<button type="button" class="btn btn-outline-danger" data-bs-toggle="modal" data-bs-target="#loginModal">
Login
</button>
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Sign In</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<button id="login" class="btn btn-login btn-md">Log In</button>
<button id="regis" class="btn btn-login btn-md">Register</button><hr style="margin-top: 0px;">
<div class="" id="login">
<form method="POST" action="">
{{ login_form.hidden_tag() }}
<fieldset class="form-group">
<div class="form-group">
{% if login_form.email_login.errors %}
{{ login_form.email_login(class="form-control form-control-md is-invalid") }}
<div class="invalid-feedback">
{% for error in login_form.email_login.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ login_form.email_login(class="form-control form-control-md mb-2", placeholder="Email") }}
{% endif %}
</div>
<div class="form-group">
{% if login_form.password_login.errors %}
{{ login_form.password_login(class="form-control form-control-md is-invalid") }}
<div class="invalid-feedback">
{% for error in login_form.password_login.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ login_form.password_login(class="form-control form-control-md mb-2", placeholder="Password") }}
{% endif %}
</div>
<div class="form-check">
{{ login_form.remember(class="form-check-input") }}
{{ login_form.remember.label(class="form-check-label") }}
</div>
</fieldset>
<div class="form-group">
{{ login_form.submit_login(class="btn btn-danger") }}
<small class="text-muted ml-2">
Forgot Password?
</small>
</div>
</form>
</div>
<div class="" id="regis">
<form method="POST" action="">
{{ regis_form.hidden_tag() }}
<fieldset class="form-group">
<div class="form-group">
{% if regis_form.username_regis.errors %}
{{ regis_form.username_regis(class="form-control form-control-md is-invalid") }}
<div class="invalid-feedback">
{% for error in regis_form.username_regis.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ regis_form.username_regis(class="form-control form-control-md mb-2", placeholder="Username") }}
{% endif %}
</div>
<div class="form-group">
{% if regis_form.email_regis.errors %}
{{ regis_form.email_regis(class="form-control form-control-md is-invalid") }}
<div class="invalid-feedback">
{% for error in regis_form.email_regis.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ regis_form.email_regis(class="form-control form-control-md mb-2", placeholder="Email") }}
{% endif %}
</div>
<div class="form-group">
{% if regis_form.password_regis.errors %}
{{ regis_form.password_regis(class="form-control form-control-md is-invalid") }}
<div class="invalid-feedback">
{% for error in regis_form.password_regis.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ regis_form.password_regis(class="form-control form-control-md mb-2", placeholder="Password") }}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ regis_form.submit_regis(class="btn btn-danger") }}
</div>
</form>
</div>
</div>
</div>
</div>
</div>
The two "Log In" and "Register" buttons are tabs i.e. by clicking on "Register" button you will see registration form and vice versa which is controlled by JavaScript.
My forms.py file looks like this:
forms.py
class RegistrationForm(FlaskForm):
username_regis = StringField('Username',
validators=[DataRequired(), Length(min=2, max=20)])
email_regis = StringField('Email',
validators=[DataRequired(), Email()])
password_regis = PasswordField('Password', validators=[DataRequired()])
submit_regis = SubmitField('Sign Up')
class LoginForm(FlaskForm):
email_login = StringField('Email',
validators=[DataRequired(), Email()])
password_login = PasswordField('Password', validators=[DataRequired()])
remember = BooleanField('Remember Me')
submit_login = SubmitField('Login')
and below is the routes.py function:
routes.py
#app.route("/", methods=['GET', 'POST'])
def home():
login_form = LoginForm()
regis_form = RegistrationForm()
if request.method == 'POST':
if login_form.validate_on_submit() and login_form.submit_login.data:
user = User.query.filter_by(email=login_form.email_login.data).first()
if user and bcrypt.check_password_hash(user.password, login_form.password_login.data):
login_user(user, remember=login_form.remember.data)
next_page = request.args.get('next')
return redirect(next_page) if next_page else redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
if regis_form.validate_on_submit() and regis_form.submit_regis.data:
hashed_password = bcrypt.generate_password_hash(regis_form.password_regis.data).decode('utf-8')
user = User(username=regis_form.username_regis.data, email=regis_form.email_regis.data, password=hashed_password)
db.session.add(user)
db.session.commit()
flash('Your account has been created! You are now able to log in', 'success')
return redirect(url_for('home'))
return render_template('home.html', login_form=login_form, regis_form=regis_form)
Now, The problem is that when I try to login using an email that is not registered it flashes me
'Login Unsuccessful. Please check email and password'
which is ok as it should do this. but when I open the login modal again and open the registration tab, the * username_regis password_regis and email_regis* fields are showing me 'The field is required' error.
It should not show me this error on registration form because I never submitted this form.
I want to get rid of these error messages. I will deeply appreciate any help.
The code you wrote is as follows:
if request.method == 'POST':
if login_form.validate_on_submit() and login_form.submit_login.data:
<SNIP>
if regis_form.validate_on_submit() and regis_form.submit_regis.data:
<SNIP>
That means that both forms are are validated, no matter what form you submit. So when you submit one form the other will always show errors. The preferred solution is to post to different routes. On your form the action parameter will need to be filled and you will need two functions, one for each route. You than will also get rid of asking if form data is available. It must be, because you are on that route.

Django 2 form in modal

Im tries to open in Django the user edit form in Bootstrap modal. But the form is empty, only the save button is shown. But I don't understand how I can make the connection. If I call the edit page directly, then I can edit the user
127.0.0.1:8000/account/edit/
index.html, includes the referral to the form
{% extends 'base.html' %}
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form action="{% url 'account:edit_profile' %}">
<input type="submit" value="Edit" />
</form>
<form action="{% url 'account:change_password' %}">
<input type="submit" value="Change Login" />
</form>
<br>
Open Modal
<br>
<div class="control-label col-sm-2">
First name:
</div>
<div class="col-sm-2">
{{ user.first_name }}
</div><br>
<div class="control-label col-sm-2">
Last name:
</div>
<div class="col-sm-2">
{{ user.last_name }}
</div><br>
<div class="control-label col-sm-2">
Email:
</div>
<div class="col-sm-2">
{{ user.email }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="edit-profile-modal" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" align="center">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</div>
<div id="div-forms">
{% include "account/edit_profile.html" with form=form %}
</div>
</div>
</div>
</div>
{% endblock %}
edit_profile.html
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-6">
<div class="panel panel-default">
<div class="panel-body">
<h3>Profile</h3>
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form method="post">
{% csrf_token %}
{{ user_form.as_p }}
<button type="submit">Save</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
views.py
def edit_profile(request):
if request.method == 'POST':
user_form = EditUserForm(request.POST, instance=request.user)
if all([user_form.is_valid(), profile_form.is_valid()]):
user_form.save()
return render(request, 'account/index.html')
else:
user_form = EditUserForm(instance=request.user)
args = {'user_form': user_form}
return render(request, 'account/edit_profile.html', args)
urls.py
urlpatterns = [
...
url(r'^edit/$', views.edit_profile, name='edit_profile'),
...
]
forms.py
class EditUserForm(forms.ModelForm):
class Meta:
model = User
fields = (
'email',
'first_name',
'last_name'
)
Im using:
Python 3.6.3
Django 2.0.7
Windows 8.1
Bootstrap 3.3.6
JQuery 1.12.0
I think that variable form doesn't exist and you use in template just user_form not form variable
{% include "account/edit_profile.html" with form=form %}
Try use it:
{% include "account/edit_profile.html" with user_form=user_form %}
Maybe you could try the code I wrote and you can find it at django-bootstrap-modal-forms. You will be able to bind your form to the modal and all of the validation stuff will work out of the box.
You will create a trigger element opening the modal
Your selected form will be appended to the opened modal
On submit the form will be POSTed via AJAX request to form's URL
Unsuccessful POST request will return errors, which will be shown under form fields in modal
Successful POST request will redirects to selected success URL

How to custom the fields in flask-wtf forms

there.
I defined a class called LoginForm:
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Length(5, 64), Email()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember me')
submit = SubmitField('Log In')
Then I render it in the templates login.html:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
It looks like above:
And I think it is a little bit ugly. So, I render the fields in the normal way:
<form action="" method="POST" role="form" class="form">
{{ form.hidden_tag() }} {{ wtf.form_errors(form, hiddens="only") }}
<div class="form-group required">
<label class="control-label" for="email">Email</label>
{{ form.email(class="form-control",id="email",required="required",type="text",value="",placeholder="Enter email") }}
</div>
<div class="form-group required">
<label class="control-label" for="password">Password</label>
{{ form.password(class="form-control",id="password",required="required",type="password",value="",placeholder="Enter email") }}
</div>
<div class="checkbox">
<label>
<input id="remember_me" name="remember_me" type="checkbox" value="y"> Remember me
</label>
</div>
{{ form.submit(class="btn btn-success btn-block") }}
Register
</form>
It agrees with me now. But I met a problem: When I click the green login button, it does not validate the data(like the format of a email address). How should I solve this problem?
First I thought that it is not validating. Thank #BurhanKhalid for reminding me.
It's just not showing the errors. I changed the code and it works.
{% if form.email.errors %}
<div class="form-group required has-error">
{{ form.email(class="form-control",id="email",required='required',type="text",value="",placeholder="Enter email") }}
{% for error in form.email.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
{% else %}
<div class="form-group required">
{{ form.email(class="form-control",id="email",required='required',type="text",value="",placeholder="Enter email") }}
{% endif %}
</div>

Python, Flask Method Not Allowed

I am currently learning python and am trying to write an app. I have the basics done. I followed a tutorial which was helpful but have gotten stuck. My understanding is 100% up to scratch yet so any help and reasoning behind it would be great.
I am getting a Method Not Allowed Error when trying to submit a form. I will post the code below and hopefully someone can help.
new_action.py
{% extends "base.html" %}
{% block content %}
<h2>New Action Request</h2>
{% include 'flash.html' %}
<div class="well">
<form class="form-horizontal" action="" method="post" name="post">
{{ form.hidden_tag() }}
<div class="control-group{% if form.errors %} error{% endif %}">
<label class="pull-right" for="post">Date: {{
datetime.date(datetime.utcnow()) }}</label>
<div class="controls">
{{form.timestamp}}
</div>
<label class="control-label" for="post">Raised By:</label>
<div class="controls">
{{ form.raised_by }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Source:</label>
<div class="controls">
{{ form.source }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Category:</label>
<div id="radios1" class="controls" data-toggle="buttons-radio">
<button type="button" class="btn active" name="health_safety" value="health_safety">Health &
Safety</button>
<button type="button" class="btn" name="quality" value="quality">Quality</button>
<input type="hidden" name="category" value={{request.form['category']}} />
</div><br/>
<br/>
<label class="control-label" for="post">Sub-Category:</label>
<div class="controls">
{{ form.sub_category }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post" width="80%" >Description:</label>
<div class="controls" >
{{ form.issue }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
<br/>
<label class="control-label" for="post">Immediate Action:</label>
<div class="controls">
{{ form.immediate_action }}
{% for error in form.errors.post %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="btn btn-primary" type="submit" value="Submit Action Request">
</div>
</div>
</form>
</div>
{% endblock %}
Views.py
#app.route('/new_action', methods=['GET', 'SET'])
#login_required
def new_action():
form = ActionRequestForm()
if request.method == 'POST':
return redirect(url_for('index'))
#actionrequest = ActionRequest(id = form.id.data, category = form.category.data)
'''post = Post(body=form.post.data, timestamp=datetime.utcnow(),
author=g.user)
db.session.add(post)
db.session.commit()
flash('Your post is now live!')'''
return render_template('new_action.html',
user = user,
form = form,
datetime = datetime
)
Your form is trying to POST data to the server. This is a HTTP POST request. You define GET and SET methods in your view. You need to use POST there.
#app.route('/new_action', methods=['GET', 'POST']) # Changed SET to POST here
#login_required
def new_action():
# ... what ever...
You should go through this RFC for HTTP. There is no SET-method.
#app.route('/new_action', methods=['GET', 'SET'])
This line of code is only allowing "GET" and "SET" methods, while you are trying to "POST" to that route.

Categories

Resources