Flask 405 error even though I've put Get in methods - python

I'm building a simple flask app. It accepts numbers from a form, calculates a value from these and then gives it back to the user. I am struggling with an error which keeps popping up saying that 'The method is not allowed for the requested URL.' I (think) ive correctly included the get and post methods for this so im not sure why im getting this error. The app has a wsgi.py type set up. Code is below:
In routes.py:
#app.route('/extraplace/advancedcalculator', methods=['GET', 'POST'])
def calculator():
form = Extraplacecalculatorform()
chanceep = 1.555
investmentreturn= 1.555
if request.method == 'POST':
back_odds = form.back_odds.data
ran = form.Number_running.data
chanceep = calculate_chanceep(back_odds, ran)
investmentreturn = (chanceep * form.back_odds.data)
return render_template('completedcalculator.jinja2', chanceep=chanceep, form=form, investmentreturn=investmentreturn)
In completedcalculator.jinja2:
{% block body %}
<h1>Input your information</h1>
<div class="formwrapper">
<h2 class="title">Contact</h2>
<form method="POST" action="/">
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>
<div class="form-lay_odds">{{ form.lay_odds.label }} {{ form.lay_odds }}</div>
<div class="form-extraplace_payout">{{ form.extraplace_payout.label }} {{ form.extraplace_payout }}</div>
<div class="form-Number_running">{{ form.Number_running.label }} {{ form.Number_running }}</div>
<div class="submit-button"> {{ form.submit }}</div>
</form>
</div>
<br>
<br>
{% if chanceep == 1.555 %}
<div>
<a class="btn btn-success" role="button">From analysis of over 10,000 horse races in the past 10 years. Our model predicts a {{chanceep}}% chance that the horse will finish in the extraplace meaning that you will have a {{investmentreturn}}% return of investmentĀ»</a>
</div>
{% endif %}
{% endblock %}
The idea behind the code is that by declaring the values of chanceep every time the page is accessed, the value of chanceep could be 1.555 if it is a get request, or the new calculated value if it is a post request. Then in the Jinja file, it will only show the bottom button with details of the calculations if the value is not 1.555 (it is currently only showing if it is 1.555 however for simplicity).
I am able to access the page for the first time however I get the error as soon as I try to post. If anyone has any ideas why this might be I would really appreciate it.

ANSWER:
I solved this issue by changing the code within the formwrapper from:
<div class="formwrapper">
<h2 class="title">Contact</h2>
<form method="POST" action="/">
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>
to:
<div class="formwrapper">
<form method="POST" enctype="multipart/form-data">
{{ form.csrf_token }}
<div class="form-back_odds">{{ form.back_odds.label }} {{ form.back_odds(size=20) }}</div>

Related

Is there a way to make a field appear when you click a button in FlaskForm?

I am in the process of designing a website for the Latin language. In the website, I have a feature called "Form Practice," where users can either enter a latin word OR choose a random verb, random adjective, random noun, random participle, or a random pronoun. You can see this layout of the feature in the image below:
Form Practice Feature
As you can see from the image, there are many fields that the user can input. I store all of this information in a Flask Form in a python file, as shown below:
from flask import render_template, request, json, Response, redirect, flash, url_for, session
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, HiddenField, RadioField
from wtforms.validators import DataRequired
class FormPracticeForm(FlaskForm):
form_name = HiddenField('Form Name')
LatinWord = StringField("Enter a word:", validators=[DataRequired()], id="LatinWord", render_kw={'onkeypress': 'handle(event)'} )
Macrons = RadioField(
u'Enter your choice:',
choices=[
('Yes', 'Yes'),
('No', 'No')],
validators=[DataRequired()])
AdjectiveRandomButton = SubmitField("Random Adjective")
NounRandomButton = SubmitField("Random Noun")
VerbRandomButton = SubmitField("Random Verb")
ParticipleRandomButton = SubmitField("Random Participle")
PronounRandomButton = SubmitField("Random Pronoun")
NextButton = SubmitField("Next", render_kw={'autofocus': True})
Then, in the actual HTML file, I reference the flask form and also handle potential errors:
{% extends "layout.html" %}
{% block content %}
<div class="container">
<form name="login" action="" method="post" novalidate>
<fieldset class="form-group">
{{ form.hidden_tag() }}
<div class="container">
<br>
<h2> Form Practice </h2> <br>
<div class="alert alert-info" role="alert">
This feature allows you to practice your word forms.
Please enter a word or select a random word. In addition, please specify whether or not you want to use macrons to get started!
<br>
<br>
NOTE: If you haven't learned a particular form yet, feel free to leave it blank - it will not be counted towards your score.
</div>
</div>
<div class="container">
<br>
<b> Use Macrons: </b>
<div class="form-group">
{% for subfield in form.Macrons %}
<div class="form-check">
{{ subfield }}
{{ subfield.label }}
</div>
{% endfor %}
{% for error in form.Macrons.errors %}
<span class="error-message">{{ error }}</span>
{% endfor %}
</div>
</div>
<div class="container">
<br>
<b> Enter a Latin word: <br> </b>
{{ form.LatinWord(size=35) }}
{% for error in form.LatinWord.errors %}
<span class="error-message"> {{ error }} </span>
{% endfor %}
<br>
<br>
<b>OR click one of the buttons to generate a random word</b>
</div>
<div class="row">
<div class="col">
{{ form.VerbRandomButton() }}
</div>
<div class="col">
{{ form.AdjectiveRandomButton() }} <br>
</div>
<div class="col">
{{ form.NounRandomButton() }}
</div>
<div class="col">
{{ form.ParticipleRandomButton() }}
</div>
<div class="col">
{{ form.PronounRandomButton() }}
</div>
</div>
<div class="container">
<br>
<br>
{{ form.NextButton() }}
</div>
<script>
function handle(e){
if(e.keyCode === 13){
e.preventDefault(); // Ensure it is only this code that rusn
}
}
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui.min.js"></script>
</fieldset>
</form>
</div>
{% endblock %}
I am not necessarily running into any problems right now, but I am stuck. I want to make it so that when the user clicks on the "Random Noun" button, for example, a multi-select field catered to nouns appears below the button that the user can select. And then if the user wants to change their mind and wants to select a "Random Verb", the multi-select field that was there disappears and a new one appears under the "Random Verb" button and that is specialized to verbs. I am unsure how to do this using FlaskForms. I was considering switching AdjectiveRandomButton, NounRandomButton, VerbRandomButton, ParticipleRandomButton, and PronounRandomButton to a RadioField as a start, but am unsure where to go from there.
Any help would be appreciated, thanks so much!
Well you could try using if/else conditions but that would be very hard to do it and it might get deeply nested as you project grows. I would suggest to switch from flask forms to JavaScript + jQuery. Basically what I do is I set up the front-end using flask-wtf so it would send a SECRET_KEY to validate the request in the back-end when submitting a form and sending it using jQuery ajax call https://api.jquery.com/jQuery.post/. Then using JavaScript you can quite easy manipulate data-flow and it's presentation / appearance as you have all the access to UI document elements.

Flask button generated with wtforms not triggering POST request

I'm writing a Flask application that works sort of like a blog. I generated the text boxes with wtforms, but whenever I click on the button to save the text, nothing happens. I get no errors.
I've tried adding print statements to my code, and everything is working fine except that Flask is not receiving the POST request. Clicking the button does absolutely nothing.
This is the code for the endpoint. I added a print() statement after if request.method but nothing printed out, so I'm assuming it's not receiving the POST request:
#app.route("/newtext", methods=["GET", "POST"])
#login_required
def newtext():
form = NewPost()
if request.method == "POST" and form.validate():
new_post = Texts(user_id=current_user.id, title=form.title.data, content=form.content.data)
db.session.add(new_post)
db.session.commit()
new_click = UserActions(user_id=current_user.id, action=4)
db.session.add(new_click)
db.session.commit()
last_text = db.session.query(Texts).order_by(Texts.id.desc()).first()
text_id = last_text.id
text_version = TextVersions(content=form.content.data, user_id=current_user.id, text_id=text_id)
db.session.add(text_version)
db.session.commit()
plaintext = BeautifulSoup(form.content.data)
text_summary = Grammar.summary(plaintext.get_text())
return render_template("summary.html", text_id=text_id, text_summary=text_summary)
else:
return render_template("basiceditor.html", form=form)
And this is the html code for the webpage. It renders okay (the GET method clearly works) but the button does nothing:
<div class="container mt-5">
<div class="content-section">
<form method="POST" action="/newtext">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">{{ legend }}</legend>
<div class="form-group">
{{ form.title.label(class="form-control-label") }}
{% if form.title.errors %}
{{ form.title(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.title.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.title(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.content.label(class="form-control-label") }}
{% if form.content.errors %}
{{ form.content(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.content.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.content(class="form-control form-control-lg", id="controleditor") }}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-success") }}
</div>
</form>
</div>
</div>
The app reports no errors. It should save the text to the database and send the person to the summary.html page, but clicking on the button does nothing. I am completely stumped.

how to pass context variable from a template to a view in django

I have one html page which shows me the list of all passengers reading it from db looks something like below and the code snippet below the image:
Forms.py
<form action="{% url 'test' %}" method="POST">
{% for record in obj %}
<div class="container">
{% csrf_token %}
<div class="card">
<div class="card-body">
<div class="row">
<div class="col">{{ record.id }}</div>
<div class="col">{{ record.detination }}</div>
<div class="col">{{ record.arrivaltime }}</div>
<div class="col">{{ record.gender }}</div>
<div class="col">{{ record.luggage }}</div>
<div class="col">{{ record.flag }}</div>
<div class="col">{{ record.phonenum }}</div>
<button id="button1">Request</button>
</div>
</div>
</div>
</div>
{% endfor %}
</form>
As you can see each entry has a request button associated to it,so on each single click i want that particular entry to get stored in Db.
I have a view which take the request from the template and should store those 7 parameters values which are inside div tags in db.
Views.py
def test(request):
form = BlogCommentsForm(request.POST)
if form.is_valid():
form.save()
The problem is when i get the request in the view there are two problems i can see:
My form returns is_valid() as Flase.
all the object list getting
passed rather than a single entry.
The results of request.POST were supposed to bejust for a single click of entry, butresulted in some dictionary like below having all the objects from the db than a single one
Request.POST gives me the result like :
<QueryDict: {'csrfmiddlewaretoken': ['sqvfMziME3T7L0VQOUF7H3Po3etfqmsvf4SbH57Fk28DkbiiGBa7dNQF2lazcM7W', 'sqvfMziME3T7L0VQOUF7H3Po3etfqmsvf4SbH57Fk28DkbiiGBa7dNQF2lazcM7W', 'sqvfMziME3T7L0VQOUF7H3Po3etfqmsvf4SbH57Fk28DkbiiGBa7dNQF2lazcM7W', ]}>
I don't exactly know where i am doing the things wrong. Can someone help me on this?

Django - ManagementForm data is missing or has been tampered with

I've been racking my brain over this problem for the past few days and I've read numerous other questions regarding the same error but they all seem to be different cases (not including management form, forgetting to update TOTAL_FORMS, etc etc) and do not resolve my problem. I have a page which could contain multiple formsets in a single HTML form. When I am posting the data back to the server, it fails on the is_valid() check for the formsets with the error in the title. I am new to web development and Django so please forgive me if I made a silly mistake or am taking an approach that will not work.
def purchase(request):
return generic_form_view(request, "inventory_tracking/add_purchases.html",
"Successfully added purchases for %s.",
PurchaseForm,
[formset_factory(PurchaseForm.LiquorForm),
formset_factory(PurchaseForm.NonLiquorForm)])
def generic_form_view(request, template, success_message, ParentForm, FormSets):
if request.method == 'POST':
request_params = copy(request.POST)
parent_form = ParentForm(request_params)
formsets = list(map(lambda form_set: form_set(request_params), FormSets))
if parent_form.is_valid(): # This works.
for formset in formsets:
if formset.is_valid(): # Fails here.
Here is a snippet from my template:
<form action="{% block form_action %}{% endblock %}" method="post">
{% csrf_token %}
<div class="row">
<div class="row">
<div class=" well well-lg">
<div class="row">
{{ parent_form.management_form }}
{% for field in parent_form %}
<div class="col-lg-6">
<div class="form-group">
<label class="control-label">{{ field.label }}</label>
{{ field }}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="row">
{% for formset in formsets %}
{{ formset.management_form }}
<div class="row">
<div class="well well-lg">
{% for form in formset %}
<div id="{{ form.prefix }}" class="row">
...
I've been trying to debug this and I noticed something a little interesting but since I am not too familiar with Django it could be a red herring. In the POST, I see the management_form data for the formsets I am creating but I do not see the management_form data for the parent formset (in this case PurchaseForm). However the parent_form is passing validation and the other formsets are not.
I expected this to be a silly problem and I turned about to be right! When my generic_form_view method creates the formsets on the GET request I was adding a prefix like the documentation mentioned but I was not adding a prefix when creating the formsets on the POST.

WTForms when rendering two forms on the same page with a Recaptcha fields only one is displayed

I am using Flask with WTforms. I am also using the WTFRecaptcha plugin in order to use Captcha fields.
Turns out I need to use two forms on the same page. When I assign a captcha field on each form, one of the captchas is not rendered on the .html page. This is because the captcha is ALWAYS created with the same ID:
Captcha and forms declaration on my forms.py file:
from wtforms import PasswordField, StringField, validators, widgets, RadioField
from wtforms.form import Form
from wtfrecaptcha.fields import RecaptchaField
class FirstForm(Form):
"""First Form"""
#Omitting fields here
captcha_1 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
class Secondform(Form):
"""Second Form"""
#Omitting fields here
captcha_2 = RecaptchaField('Captcha', [], public_key='OMITTING_PUBLIC_KEY', private_key='OMITTING_PRIVATE_KEY', secure=True)
Route declaration:
#!/usr/bin/env python
from flask import Flask, render_template, request
from flask.ext.assets import Environment
from forms import FirstForm, SecondForm
from flask import request
from flask import jsonify
#app.route('/test')
def test_form():
"""Test."""
form_1 = FirstForm(request.form, captcha_1={'ip_address': request.remote_addr})
form_2 = SecondForm(request.form, captcha_2={'ip_address': request.remote_addr})
if request.method == 'POST' and (form_1.validate() or form_2.validate()) :
return "Instructions have been sent to your e-mail"
return render_template(
'test-form.html',
title='Get Started',
form_1=form_1,
form_2=form_2
)
test-form.html
{% extends "base.html" %}
{% block content %}
<div class="container block-form">
<div class="row first">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_1 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
<div class="row second">
<div class="col-xs-12 col-md-7 border-right">
<h1 class="title">{{ title }}</h1>
<p>{{ description }}</p>
<div class="form-area">
<form method="post">
{% for field in form_2 %}
<div class="form-group{% if field.errors %} has-error has-feedback{% endif %}">
<div class="row">
<div class="col-xs-12 col-md-4">
{{ field.label(class="control-label") }}
</div>
<div class="col-xs-12 col-md-8">
{{ field(class="form-control") | safe }}
</div>
</div>
{% if field.errors %}
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
{% endif %}
{% for error in field.errors %}
<p class="help-block text-danger">
<span class="glyphicon glyphicon-remove"></span>
{{ error }}
</p>
{% endfor %}
</div>
{% endfor %}
<br>
<button type="submit" class="btn btn-gradient">Submit</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Code rendered for captcha in form_1 (Up to the div element):
<script src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" type="text/javascript">
//Other code here omitted
<script src="https://www.google.com/recaptcha/api/js/recaptcha.js" type="text/javascript">
//Other code here omitted
<div id="recaptcha_widget_div" class=" recaptcha_nothad_incorrect_sol recaptcha_isnot_showing_audio">
Code rendered for captcha in form_2 (Up to the div element):
<script type="text/javascript" src="https://www.google.com/recaptcha/api/challenge?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp">
<script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha.js"/>
<div id="recaptcha_widget_div" style="display: none;"/>
<noscript><iframe src="https://www.google.com/recaptcha/api/noscript?k=6LeCJvUSAAAAAAvqwJEueVdV0wyNLPtX6KWSTdXp" height="300" width="500" frameborder="0"></iframe>
<br> <textarea name="recaptcha_challenge_field" rows="3" cols="40"> </textarea> <input type="hidden" name="recaptcha_response_field" value="manual_challenge"></noscript>
RESULT: Only one captcha is shown.
... Therefore if I have two captcha fields (Possible on two different forms), one won't display.
Any solutions/suggestions?
This is well a well documented limitation of Recaptcha
Currently, the Google captcha mechanism offer only one captcha form per page
I would encourage you to rethink the way you are organizing your page. Forms in HTML are simple by design. Most of the tooling built around them assumes that a page does one thing and submits the result to the server in a single form submission.
Disclaimer: I don't really know anything about your code. Proceeding regardless: it smells like your design might be a too clever. What I mean by this is that if you haven't seen it done somewhere else and google's tooling doesn't support it the issue is probably with your approach.
If you need to commit the result of a single stateless transaction then a <form> is appropriate and WTForms is a great tool to generate it. If you need something richer you might consider the following:
Break your forms out into multiple pages. A simple set of hyperlinks can provide an easily navigable hierarchy.
Build your DOM with javascript and submit to a RESTful endpoint(you can even use WTForms for validation by converting the request body into a MultiDict and Recaptcha supports AJAX)
Build your <form> dynamically with javascript and switch the action to correspond to the correct form processor on your server.
This is not possible with reCAPTCHA.
See the related ASP.NET question: Multiple reCAPTCHAs in one ASP.Net page
And for possible workarounds: How do I show multiple recaptchas on a single page?

Categories

Resources