Issue with csrf_token while using Flask and WTForms - python

I'm trying to set up a basic "Contact" form for my website, which will basically take in values and then put them into a CSV file. The issue I'm having is that the entries cannot be validated cause they're missing a csrf_token?
Here's the relevant code from my app.py:
#app.route('/contact_end', methods=['POST'])
def handle_contact():
form = ContactForm()
print(form.name.data)
if form.validate_on_submit():
print("yup")
with open('data/messages.csv', 'a') as f:
print("oh shit")
writer = csv.writer(f)
writer.writerow([form.name.data, form.email.data, form.message.data])
print("waddup")
return redirect(url_for('contact_handler.html'), name=form.name.data)
print(form.errors)
return render_template('contact.html', form=form)
It skips over the if statement as it never ends out printing the "yup", and instead it prints out the error:
{'csrf_token': ['The CSRF token is missing.']}
The template that this connects to is:
{% extends "base_template.html" %}
{% block title %}Contact us {% endblock %}
{% block content %}
<p>Feel free to use the contact form below to send us any questions you might have.</p></br>
<form action="/contact_end" method="post">
{{ form.csrf_token }}
<label>Your Name <input type="text" name="name"/></label></br>
<label>Your Email <input type="text" name="email"/></label></br>
<label>Your Name <textarea name="message"></textarea></label></br>
<button type="submit">Send</button>
<button type="reset">Clear</button>
</form>
{% endblock %}
I've tried messing with form.csrf_token and .hidden_tags(), but with no success.
As well, this is the initial part of app.py that brings you to the page in the first place, the one above is the endpoint for the form:
#app.route('/contact')
def contact():
return render_template('contact.html', form=form)
Finally, here's my ContactForm class:
class ContactForm(FlaskForm):
print("yep")
name = StringField('Name', validators=[InputRequired()])
email = EmailField('Email', validators=[InputRequired(), Email()])
message = TextAreaField('Message', validators=[InputRequired()])
I've made sure to set my secret key, as well. Anyone have any idea why this isn't working? Many thanks.

You still need to create the form instance in your contact() function:
#app.route('/contact')
def contact():
form = ContactForm()
return render_template('contact.html', form=form)

Related

Error message on entering duplicate in django form

I am trying to avoid duplicate email in my website form . Till now I was able to do this:
1.Whenever I enter duplicate email, it navigate back to homepage and user is not saved{ In my case team is not joined}.
2.In admin page when I try to enter duplicate email , I get my error message of duplicate email address
I want this message in my form too, but it navigates to homepage.
This is my model in models.py:
class Team(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField(max_length=100,unique=True,error_messages={'unique':"Email already exists"})
contact=models.IntegerField(null=False,blank=False,default=1234567890)
def __str__(self):
return self.username
This is my form in forms.py:
class TeamMembers(forms.ModelForm):
username = forms.CharField(required=True,max_length=100)
email = forms.EmailField(required=True,max_length=100,error_messages={'unique':"Email already exists"})
contact=forms.IntegerField(required=True)
class Meta:
model=Team
fields = ['username','email','contact']
This is my function in views.py
def join_team(request):
if request.method == "POST":
form = TeamMembers(request.POST)
if form.is_valid():
form.save()
form = TeamMembers()
messages.success(request,"Joined team")
else:
form = TeamMembers()
return render(request, 'user/join_team.html', {'form' : form })
This is my join_team.html
{% extends 'base.html' %}
{%load crispy_forms_tags%}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join our team</legend>
{{form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Join</button>
</div>
</form>
</div>
{% endblock content %}
I want to display error message on form page instead of going to homepage.
I am not able to find this question anywhere , so please help me!!

Show error message if password and username incorrect in Django form_template

I am trying to show an error when the user enters wrong login credentials using form_template. So far I tried the below approach but it is not working.
Forms.py:
class UserForm(forms.Form):
username=forms.CharField(max_length=50)
password=forms.CharField(widget=forms.PasswordInput)
model=User
fields=['username', 'password']
Views.py:
class loginform(View):
template_name='essay/Login.html'
form_class=UserForm
def get(self,request): # if the request is get then only view the function
form=self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self,request):
form=self.form_class(request.POST)
if form.is_valid():
#user = form.save(commit=False) # it doesnot save in database, it is used to et clean the values
# clean data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# authenticate user:
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
if(request.user.is_prof==True):
return redirect('essay:file', )
else:
return redirect('essay:stdprofile')
else:
return render(request,self.template_name, {
'error_message': ' Login Failed! Enter the username and password correctly', })
else:
msg = 'Errors: %s' % form.errors.as_text()
return HttpResponse(msg, status=400)
return render(request, self.template_name, {'form': form})
Form_template:
{% for field in form %}
<div class="form-group">
<label class="control-label col-sm-2">{{ field.label_tag }}</label>
<div class="col-sm-10">{{ field }}</div> <!-- inputs on the rigth -->
</div>
{% endfor %}
Login.html:
<body>
<div class="login-card">
<h1>Log-in</h1><br>
<form class="form-horizontal" action="" method="POST" enctype="multiport/form-data">
{% csrf_token %}
{% include 'essay/form_template.html' %}
<input type="submit" name="login" class="login login-submit" value="login">
</form>
{% error_message %}
</div>
</body>
The problem I got when I enter invalid credentials, username and password fields vanish and it also does not display the error message.
In your field in form page add,
{{field.errors}}
or under csrf tag add,
{{form.errors}}
This will show all your field errors, for non field errors add,
{{form.non_field_errors}}
Also, you can also use Django builtin messages to display your custom message.
The error is because you are using {% error_message %}in your template, when the correct is {{ error_message }}.
Plus,
why not use Django messages?
You also can easily include message on Class Based Views - see here

Form Validation message not being displayed - Flask

I'm having trouble getting error messages in Flask to render.
I suspect this is related to the blueprints. Previously, the logic seen in views.py was in the users blueprint, but I've since ported it over to the main blueprint. Anyhow, since then, I am unable to get error messages to render.
The specific line I think I'm having trouble with is:
self.email.errors.append("This Email is already registered")
project/main/views.py
#main_blueprint.route('/', methods=['GET', 'POST'])
#main_blueprint.route('/<referrer>', methods=['GET', 'POST'])
def home(referrer=None):
form = RegisterForm(request.form)
# prepares response
resp = make_response(render_template('main/index.html', form=form))
if form.validate_on_submit():
do_stuff()
return resp
project/main/index.html
<h1>Please Register</h1>
<br>
<form class="" role="form" method="post" action="">
{{ form.csrf_token }}
{{ form.email(placeholder="email") }}
<span class="error">
{% if form.email.errors %}
{% for error in form.email.errors %}
{{ error }}
{% endfor %}
{% endif %}
</span>
</p>
<button class="btn btn-success" type="submit">Register!</button>
<br><br>
<p>Already have an account? Sign in.</p>
</form>
project/user/forms.py
class RegisterForm(Form):
email = TextField(
'email',
validators=[DataRequired(), Email(message=None), Length(min=6, max=40)])
def validate(self):
print "validating"
initial_validation = super(RegisterForm, self).validate()
if not initial_validation:
print "not initial validation"
return False
user = User.query.filter_by(email=self.email.data).first()
print user
if user:
print self
print "error, email already registered"
self.email.errors.append("This Email is already registered")
return False
return True
When attempting to debug, the value for 'print user' from this is:
project.user.forms.RegisterForm object at 0x7fa436807698
Got it to work, #glls, you were correct.Rewrote the code as:
#main_blueprint.route('/', methods=['GET', 'POST'])
#main_blueprint.route('/<referrer>', methods=['GET', 'POST'])
def home(referrer=None):
# prepares response
resp = make_response(render_template('main/index.html', form=form))
if form.validate_on_submit():
do_stuff()
form = RegisterForm(request.form)
return resp

Multiple Django Crispy Forms In One View

When placing 2 forms in a view using the form|crispy filter and this answer to handle 2 forms in a single view: Proper way to handle multiple forms on one page in Django I am getting this error.
views.py:
def test_form(request):
if not request.user.is_authenticated():
return redirect(settings.LOGIN_URL)
title = 'test form'
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
context = {
'title': title,
'row_control_form': row_control_form,
'entry_form': entry_form,
}
if 'row_control_submit' in request.POST:
if row_control_form.is_valid():
row_control_form.save()
if 'entry_submit' in request.POST:
if entry_form.is_valid():
entry_form.save()
return render(request, "timesheet/test_form.html", context)
forms.py
class RowControlForm(forms.ModelForm):
class Meta:
model = RowControl
fields = ['month_control_record', 'department', 'activity', 'notes']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures row is unique
try:
RowControl.objects.get(month_control_record=cleaned_data['month_control_record'],
department=cleaned_data['department'],
activity=cleaned_data['activity'],
notes=cleaned_data['notes'])
except RowControl.DoesNotExist:
pass
else:
raise ValidationError('This row already exists')
# Always return cleaned data
return cleaned_data
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['row_control', 'date', 'hours']
def clean(self):
cleaned_data = self.cleaned_data
# Ensures data is unique (only 1 hours entry for each date and row_control)
try:
Entry.objects.get(row_control=cleaned_data['row_control'],
date=cleaned_data['date'])
except Entry.DoesNotExist:
pass
else:
raise ValidationError('This entry already exists')
# Always return cleaned data
return cleaned_data
test_form.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ row_control_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="row_control_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
<div class="col-md-6 col-md-offset-3">
<h1 class="page-header"> Form Test </h1>
<form method="POST" action="{{ request.path }}">
{% csrf_token %}
{{ entry_form|crispy }}
<button class="btn btn-primary" type="submit" value="Submit" name="entry_submit" ><i class="fa fa-lg fa-floppy-o"></i> Save</button> </form>
</br>
</div>
{% endblock %}
To provide context to the error:
Line 42 of forms.py is:
Entry.objects.get(row_control=cleaned_data['row_control'],
EDIT: Further investigation has shown that the issue is that both form validations are being run no matter which submit button is pressed, the request.POST when submitting valid data for the RowControlForm is:
<QueryDict: {'csrfmiddlewaretoken': ['HffmmbI31Oe0tItYDfYC4MoULQHL0KvF'], 'notes': ['Cool'], 'row_control_submit': ['Submit'], 'month_control_record': ['1'], 'department': ['1'], 'activity': ['1']}>
Therefore entry_submit is not in the request.POST and that validation should not run yet it is?
Firstly, you need to fix this line of your form's clean method
def clean(self):
...
Entry.objects.get(row_control=cleaned_data['row_control'],
You can't assume that row_control will be in the cleaned_data. You either need to add a check if 'row_control' in cleaned_data or catch the KeyError, then update the rest of the method appropriately. You should fix this, even though you didn't see this error until you put multiple forms on one page. It shouldn't be possible to cause a 500 server error by leaving a value out of a POST request. Users could do this even if there is only one form on the page.
Validation is running for both forms, because you are instantiating both forms with the post data, regardless of which submit button was pressed.
row_control_form = RowControlForm(request.POST or None)
entry_form = EntryForm(request.POST or None)
You should only use the POST data for the form you wish to submit.
row_control_form = RowControlForm()
entry_form = EntryForm()
if 'row_control_submit' in request.POST:
row_control_form = RowControlForm(request.POST)
if row_control_form.is_valid():
if 'entry_submit' in request.POST:
entry_form = EntryForm(request.POST)
if entry_form.is_valid():
entry_form.save()
Finally, it's good practice to redirect the user once they have successfully submitted a valid form.

Error passing argument to form in Django

I am new with django and I try update some data passing the id_provider from form1 to form2
The form2 have to display the data of the provider
I have an html page with a little form(form1):
Is a a simple input text where the user write a number.
the number is passed to other form as an argument.
My forms.py:
class ConfigForm(forms.ModelForm):
def __init__(self,idprov,*args,**kwargs):
super(ConfigForm,self).__init__(*args,**kwargs)
self.id_provider = idprov
class Meta:
model = Config
And my views.py:
#csrf_exempt
def configView(request):
prov = get_object_or_404(Config, id_proveedor=id)
if request.method == 'POST':
form = ConfigForm(request.post, instance=prov)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
form = ConfigForm(Config.id_proveedor,instance=prov)
return render_to_response('config.html',{'form':form},RequestContext(request))
This is the form(form2) where I try to display the data:
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-4">
<form method='POST' action='' class='form'>
<div class="form-group">
{% csrf_token %}
{{ form.as_p }}
</div>
<button type='submit' class="btn btn-primary">Grabar</button>
</form>
</div>
</div>
</div>
{% endblock %}
I receive the error:
TypeError at /config/
id() takes exactly one argument (0 given)
I don't know if my error are in the method of the form where I try to update the data (form2) or I have some error in the view of the form.
I think I am not getting the value of the input text int the right way.
Any advice, link or snippet will be very helpful
Thanks in advance
id is a Python function and you didn't create it
>>> id('test')
35092128
Try
#csrf_exempt
def configView(request):
# Get your ID in another way for example this one
pk = request.POST.get('id', None)
if pk is None:
# Handle error
prov = get_object_or_404(Config, id_proveedor=pk)
# ^^
should works
BTW using csrf_exempt is generally not a good idea.

Categories

Resources