This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
Closed 1 year ago.
i am relatively new to Flask/Python/HTML so please excuse my language.
Basically I am trying to retrieve the "name" field with request.form.get that was inputted in my HTML page. The name field was generated with a for loop in jinja. When i hit the checkbox, and click submit, i expect the request.form.get to retrieve the "name" field that was in that specific check boxes' data. However, when i test out the data, I get a 404 error that says NONE for the request.form.get value. I'm not sure where I am going wrong. I suspect it might be what I am plugging in as the name for request.form.get.
On my flask side:
#app.route("/recipedata", methods=["GET","POST"])
def recipedata():
if request.method == 'POST':
food = request.form.get("{{value.id}}")
On HTML side:
{% for value in foodinfo.results %}
<form action="/recipedata" method = "POST">
<input type="checkbox" name="{{value.id}}" value={{value.id}}>
<input type=text placeholder="{{value.id}}">
<input type="submit"> Go to Recipe info
</form>
{% endfor %}
The 2nd line in my form tag with type text was used to test whether my value.id was printing correctly in Jinja, and indeed it was. Additionally, for clarification, foodinfo is passed as a .json() object with nested dictionary key/values. Value.id allows me to access that dict's value at key 'id', I believe.
Thank you!
I don't think your function definition of recipedata() is valid as per python syntax. You need to indent code in python to preserve scope information. You can see more here.
Try with following function definition.
def recipedata():
if request.method == 'POST':
food = request.form.get("{{value.id}}")
I'm not sure if HTML part is causing any trouble.
Related
I have a Post model that requires a certain category before being added to the database, and I want the category to be generated automatically. Clicking the addPost button takes you to a different page and so the category will be determined by taking a part of the previous page URL.
Is there a way to get the previous page URL as a string?
I have added my AddPost button here.
<aside class="addPost">
<article>
<form action="/Forum/addPost">
<input type="submit" name="submit" value="Add Post"/>
</form>
</article>
</aside>
You can do that by using request.META['HTTP_REFERER'], but it will exist if only your tab previous page was from your website, else there will be no HTTP_REFERER in META dict. So be careful and make sure that you are using .get() notation instead.
# Returns None if user came from another website
request.META.get('HTTP_REFERER')
Note: I gave this answer when Django 1.10 was an actual release. I'm not working with Django anymore, so I can't tell if this applies to Django 2
You can get the referring URL by using request.META.HTTP_REFERER
More info here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
I can't answer #tryingtolearn comment, but for future people, you can use request.META['HTTP_REFERER']
Instead of adding it to your context, then passing it to the template, you can place it in your template directly with:
Return
A much more reliable method would be to explicitly pass the category in the URL of the Add Post button.
You can get the previous url in "views.py" as shown below:
# "views.py"
from django.shortcuts import render
def test(request):
pre_url = request.META.get('HTTP_REFERER') # Here
return render(request, 'test/index.html')
You can also get the previous url in Django Template as shown below:
# "index.html"
{{ request.META.HTTP_REFERER }}
I am creating quiz-like web application for learning languages using Flask, Jinja, WTForms, SqlAlchemy etc. Once an user completes such a language course by successfully going through all levels stored in JSON file I want the app offer him a practice mode, where the user will answer randomly selected levels.
When I run the app, I can see radio buttons generated with values from random level as I want, but when I choose any answer and submit it, form.validate_on_submit() returns False and form.errors returns {'practiceform': [u'Not a valid choice']}. When I hard-code value to currentLevel variable, it works properly.
views.py
#user_blueprint.route('/courses/<course>/quiz/practice',methods=['GET','POST'])
#login_required
def practice(course):
courseClass = class_for_name("project.models", course.capitalize())
courses = courseClass.query.filter_by(email=current_user.email).first()
maxLevel = courseClass.query.filter_by(email=current_user.email).first().get_maxLevel()
currentLevel = randint(0, maxLevel-1) # If this value is hard-coded or fetched from db, it works correctly
dic = generateQuestion(course, currentLevel)
display = dic["display"]
correct = dic["correct"]
options = dic["options"]
form = PracticeForm(request.form)
form.practiceform.choices = [(option, option) for option in options]
if form.validate_on_submit():
practiceForm = form.practiceform.data
if ((practiceForm == correct) and courses):
# Do something
flash("Nice job", 'success')
return redirect(url_for('user.practice', course=course))
else:
# Do something else
flash("Wrong answer", 'danger')
return redirect(url_for('user.practice', course=course))
return render_template('courses/practice.html', form=form, display=display)
forms.py
class PracticeForm(Form):
practiceform = RadioField('practice')
practice.html
{% extends "_base.html" %}
{% block content %}
<form action='' method='POST' role='form'>
<p>
<!-- Tried put form.csrf, form.csrf_token, form.hidden_tag() here -->
{{ form.practiceform() }}
</p>
<input type="submit" value="submit" />
</form>
{% endblock %}
So what am I missing there? What makes difference between lets say hardcoded level 25, which works properly or if the number 25 is randomly generated within randint?
My guess is that option is a int, bug WTForms get a str from request.form.
When data comes back from requests it is treated as a string by WTForms unless you specify a type explicitly with the coerce kwarg of the wtforms.fields.*Field constructor:
practiceform = RadioField('practice', coerce=int)
So I found that randint() caused the problem because the practice(course) method was called on both GET and POST actions which led to having two different integers -> two different forms most of the time. So I refactored the code. kept the practice(course) method for GET action and created a new method which handles POST action and this solved the problem.
I am trying to implement a server-side check to prevent users from double-submitting my forms (Django web app).
One technique I'm trying is:
1) When the form is created, save a unique ID in the session, plus pass the unique ID value into the template as well.
2) When the form is submitted, pop the unique ID from the session, and compare it to the same unique ID retrieved from the form.
3) If the values are the same, allow processing, otherwise not.
These SO answers contributed in me formulating this.
Here's a quick look at my generalized code:
def my_view(request):
if request.method == 'POST':
secret_key_from_form = request.POST.get('sk','0')
secret_key_from_session = request.session.pop('secret_key','1')
if secret_key_from_form != secret_key_from_session:
return render(request,"404.html",{})
else:
# process the form normally
form = MyForm(request.POST,request.FILES)
if form.is_valid():
# do something
else:
# do something else
else:
f = MyForm()
secret_key = uuid.uuid4()
request.session["secret_key"] = secret_key
request.session.modified = True
return render(request,"my_form.html",{'form':f,'sk':secret_key})
And here's a sample template:
<form action="{% url 'my_view' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="sk" value="{{ sk }}">
{{ form.my_data }}
<button type="submit">OK</button>
</form>
This set up has failed to stop double-submission.
I.e., one can go on a click frenzy and still end up submitting tons of copies. Moreover, if I print secret_key_from_form and secret_key_from_session, I see them being printed multiple times, even though secret_key_from_session should have popped after the first attempt.
What doesn't this work? And how do I fix it?
UPDATE: when I use redis cache to save the value of the special key, this arrangement works perfectly. Therefore, it seems the culprit is me being unable to update request.session values (even with trying request.session.modified=True). I'm open to suggestions vis-a-vis what could be going wrong.
Note that this question specifically deals with a server-side solution to double-submission - my JS measures are separate and exclusive to this question.
You might just need request.session.modified = True. If you want to make sure that the session is deleting you can use del too.
secret_key_from_session = request.session.get('secret_key','1')
del request.session['secret_key']
request.session.modified = True
I couldn't figure out what caused the problem, but via substituting Redis cache for every request.session call, I was able to get my desired results. I'm open to suggestions.
I'm having issues with correctly sending and receiving a variable with a GET request. I cannot find any information online either. From the HTML form below, you can see I'm sending the value of 'question' but I'm also receiving 'topic' from a radio button in the form (though the code is for that is not below).
I want to send 'topic' using POST but use GET for 'question'. I'm aware that the form method is POST though I'm not sure how to cater for both POST and GET.
HTML Form:
<form method="POST" action="{{ url_for('topic', question=1) }}">
My second issue is that I'm unsure how to receive 'topic' AND 'question' from the form. I've managed to receive 'topic' as seen below but I'm not quite sure how to receive 'question'. Preferably it would be better for the URL to be like so:
www.website.com/topic/SomeTopic?question=1
For the code below, I found online that request.args[] is used for receiving GET requests though I'm not sure if it is correct.
Flask:
#app.route('/topic/<topic>', methods=['POST', 'GET'])
def questions(topic):
question = request.args['questions']
return render_template('page.html')
The question is
How do I send two variables from a form using GET and POST for different variables at the same time.
How would I go about receiving both variables?
The short answer to your question is that you can't send both GET and POST using the same form.
But if you want your url to look like you specified:
www.website.com/topic/SomeTopic?question=1
then you're almost there. First you will need to already know the name of the topic as you have to specify that in your call to url_for() for the questions url.
<form method="GET" action="{{ url_for('questions', topic_name="cars") }}">
# Your url will be generated as www.website.com/topic/cars
flask
# Note that I changed the variable name here so you can see how
# its related to what's passed into url_for
#app.route('/topic/<topic_name>')
def questions(topic_name):
question = request.args['question']
return render_template('page.html')
Now when you submit your form, your input will be sent as a GET, an asumming you have an input field with the name question you'll be able to get the value of that field.
I have a python function that takes a series of integers as inputs and returns another series of integers. I'd like to distribute the function in the form of a web app.
The landing page should consist of a web form with a series of integer fields (with input validation), drop-down fields and a submit button. The submit button triggers the said python function and returns the results which should be rendered in an html table.
I am a complete novice with web development, but after some research it appears that flask is the most appropriate framework for me to use for the above task. My problem is that the documentation I have encountered so far deals primarily with blog development and therefore not particularly relevant for the type of app I am after.
I am therefore seeking any pointers (sample code, books, articles) or guidance to get me started with my task. In its simplest form, what I'm looking for is:
web form that takes one integer (1-10) and a second integer (1-5) from a drop down list
web form returns error if user enters invalid integer (<1, >10)
on submit button python function calculates the sum of the two integers
result is presented on the web form
All guidance appreciated.
Well it's quite simple really, it's all about how you present a form in html template, getting your view to get the form data, and passing the context back to the template.
I've quickly mocked a sample like what you want (nothing fancy, just back to the basic and show you how these work together), it's only a few lines of code in 2 files main.py (core file, like a view logic) and a template calculation.html:
main.py
from flask import Flask
from flask import render_template
from flask import request
app = Flask(__name__)
#app.route("/", methods=['GET', 'POST'])
def calculation():
result = 0
error = ''
# you may want to customize your GET... in this case not applicable
if request.method=='POST':
# get the form data
first = request.form['first']
second = request.form['second']
if first and second:
try:
# do your validation or logic here...
if int(first)>10 or int(first)<1:
raise ValueError
result = int(first) + int(second)
except ValueError:
# you may pass custom error message as you like
error = 'Please input integer from 1-10 only.'
# you render the template and pass the context result & error
return render_template('calculation.html', result=result, error=error)
if __name__ == "__main__":
app.run()
templates/calculation.html
<h1>Calculation</h1>
<form method="POST">
<input type="text" name="first" value="">
<select name="second">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<input type="submit" value="Submit">
{% if result %}
<p>
<label name='result'>Answer is: {{ result }}</label>
</p>
{% endif %}
{% if error %}
<p>
<label name="error">{{ error }}</label>
</p>
{% endif %}
</form>
Hopefully these are self explanatory and you can get to understand how to work with the basic of Flask and forms etc.
Read Flask Doc, and try to follow through, they are quite simple really and once you nail the basic, you may start looking for intermediate and advance topic.
FYI, there is an extension for WTForms called Flask-WTF, it is very handy when dealing with forms, although nothing stops you just doing everything in plain html form like above code.
Hope this helps and I wish you like the simplicity and flexiblity Flask brings you.
With NiceGUI you can build such UIs with a few lines of Python:
from nicegui import ui
i = ui.number(format='%d')
j = ui.select([1, 2, 3, 4, 5])
results = ui.table({
'columnDefs': [{'field': 'i'}, {'field': 'j'}, {'field': 'sum'}],
'rowData': [],
}).classes('max-h-40')
def calculate():
if not 1 <= i.value <= 10:
ui.notify('Invalid input')
return
results.options['rowData'].append({'i': i.value, 'j': j.value, 'sum': i.value + j.value})
results.update()
ui.button('Calculate', on_click=calculate)
ui.run()
HTML, JS and CSS are not required.
For this example I made use of ui.table, which builds on AG Grid and allows you to create pretty data tables. But you could display a simple ui.label as well.
(Disclaimer: I'm one of the developers of NiceGUI.)