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.
Related
I would like to set up my URLs/endpoints according to REST as closely as possible, while still utilising Flask-WTForms.
I would like my form to render at GET /posts/new, and submit to POST /post.
With Flask-WTForms I can only work out how to get it to GET/POST to the same URL.
My current code looks like this:
#post_bp.route('/posts/new', methods=['GET', 'POST'])
def show_post_form():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return 'success'
return render_template('create_post_form.html', form=create_post_form)
However I would like to be able to make it look something more like this, but I just can't seem to work it out:
#post_bp.route('/posts/new', methods=['GET'])
def show_post_form():
create_post_form = CreatePostForm()
return render_template('create_post_form.html', form=create_post_form)
this route only shows the form
the form submits a POST request to /post
<form action="{{url_for('shipment.C_shipment')}}" method="POST" novalidate>
the POST /post route handles the submitted form and if there are errors for example, then it redirects back to GET /posts/new:
#post_bp.route('/post', methods=['POST'])
def create_post():
create_post_form = CreatePostForm()
if create_post_form.validate_on_submit():
return "success!"
if len(create_post_form.errors) != 0:
for error in create_shipment_form.errors:
for msg in create_shipment_form.errors[error]:
flash(msg)
return redirect(url_for('shipment.show_create_shipment_form'))
i guess creating a new CreatePostForm() object here doesn't really work..
Any suggestions?
Creating a new CreatePostForm is correct as it parses the submitted form data for you. This allows you to call validate_on_submit() on the form object.
I don't think you're generating the correct URL for the form action in your HTML snippet. The argument to url_for() should be the desired endpoint (see docs) which should be <post_bp>.create_post. This would be similar to your call
return redirect(url_for('shipment.show_create_shipment_form'))
If this does not fix the issue, please provide both frontend and backend error messages you receive when trying to send the data to /post.
I am using:
Flask 0.12.2
Python 3.6.1
Consider this, isolated, example of the behavior I am pondering on:
from flask import Flask, url_for, render_template_string
app = Flask(__name__)
#app.route('/hi/', methods=['POST'])
#app.route('/hi/<var>')
def hi(var):
return ''
#app.route('/')
def index():
return render_template_string('''
<html>
<head>
<title>GET or POST</title>
</head>
<body>
<form action="{{ url_for('path') }}">
<input type='SUBMIT' value='GET'>
</form>
<form action="{{ url_for('path') }}" method='POST'>
<input type='SUBMIT' value='POST'>
</form>
</body>
</html>''')
#app.route('/path/', methods=['GET', 'POST'])
def path():
return str(url_for('hi', var='Hello', var2='xyz'))
To make my intentions clear, I will briefly describe what is happening and what I am striving to understand:
/hi/ endpoint has an 'optional' parameter (<var>), which is accepted only via GET request. 'Plain' (i.e. without arguments) /hi/ endpoint can only be accessed via POST method.
/path/ endpoint can be accessed via both GET and POST http methods. And it just returns path for hi generated via url_for('hi', var='Hello', var2='xyz')
Now, I would expect /path/ to return the same string, regardless of which method was used to access it (GET or POST). But it is not the case: for GET it returns /hi/Hello?var2=xyz (as I, actually, would expect), but for POST I am getting /hi/?var=Hello&var2=xyz (which strikes me as odd behavior).
Through trials and errors I was able to find out that adding POST to methods allowed for /hi/<var> fixes the issue (/hi/Hello?var2=xyz is returned by /path/ for both GET and POST), i.e.:
#app.route('/hi/', methods=['POST'])
#app.route('/hi/<var>', methods=['GET', 'POST'])
def hi(var):
...
I hope, someone would be able to explain the following, for me:
Why is this (/path/ returns different values for POST and GET) happening?
Is it possible to avoid this behavior, without allowing POST on /hi/<var>?
I have stumbled upon answers thanks to another question =)
Addressing my own questions:
(not 100% sure about that, would be grateful if someone confirmed that I am correct here) url_for has an optional _method parameter, which is defaulted to the method that was used to return current view. So, /path/ is really returning return str(url_for('hi', var='Hello', var2='xyz', _method='GET') when it was accessed via GET request and return str(url_for('hi', var='Hello', var2='xyz', _method='POST') if it was accessed via POST request. That is why allowing POST on both endpoints (/hi/<var> and /hi/) fixes the problem — if POST is allowed only for /hi/, then return str(url_for('hi', var='Hello', var2='xyz', _method='POST') is checking whether var is known only to /hi/ (and it is, obviously, is not known to it). On the other hand, if POST is allowed on both endpoints, then /hi/ and /hi/<var> are checked for the presence of var and /hi/<var> is correctly selected.
Given the previous point, the fix is pretty obvious now: return str(url_for('hi', var='Hello', var2='xyz', _method='GET') should be substituted for return str(url_for('hi', var='Hello', var2='xyz'), in the original snippet.
I have the form which i am showing by normal view. Then i am send the GET parameters to djnago ChangeList view like django does for lookups like this
student/?region__id__exact=1&status__exact=Published
now is there any way to remove that from the URL in the address bar.
I don't users to see what i am doing
The whole point of GET is that they are retrieved from the URL itself, removing them from the URL removes them entirely.
If you want them 'hidden' you will need to use POST.
The HTTP GET method of form submission passes the information from template to views through URL. If you want to "hide" information from URL use POST instead. In your form do like this:
<form action="/view_name/" method="post">
and in views:
request.POST['name']
i am having this weird url reaction.
this is my views.py
def user_edit(request):
user = User.objects.get(id=request.GET.get('userid'))
return render_to_response("editprofile.html",{'user':user},context_instance=RequestContext(request))
and this is my form.
<form action="/update_userprofile/?userid={{user.id}}" ...
my urls.py
url(r'^update_userprofile/','home.views.update_userprofile')
but once i send the form, i am getting error:
Internal Server Error: /update_userprofile/on
where is that on coming from? i dont understand what happens here.
thanks a lot .
OK I try your codes. You did not put in your question what method did you use. So I try the GET and the output User matching query does not exist. I try the POST and it works now.
<form action="/update_userprofile/?userid={{user.id}}" method="POST">
Even though you have user id define in your url, you can still get the value from the method POST.
UPDATE:
You code is fine, just change the method into method=POST in your form
I'm trying to send a HTML form input from a page to a python script. This is just for testing purposes so ignore the poor code. Basically I don't know how to define the action= part to reference the search() function in the python script. I just need to get the basic functionality working. I'm using web2py as the framework which is probably relevant:
Controller: default.py
def index():
return dict()
def search():
import urllib
q=request.vars.q
result1 = urllib.urlopen('http://www.google.com/search?q=%s' % q)
return dict(result1=result1)
default/search.html:
{{extend 'layout.html'}}
<form method=get action=???>
<input name=q>
<input type=submit value=search>
</form>
It looks like the form itself is served via the search() function, so you can just set action="", and it will submit back to the search() function. Also, you should put quotes around your HTML attribute values, and you should add some logic to check whether there is anything in request.vars.q, because when the page first loads with an empty form, there is no query to process.
What you are doing there is correct for GET requests. For POST requests you need to pass the fields as the data parameter.
urllib.urlopen('http://www.google.com/search', data=urllib.urlencode({'q':'FOO'}))
does the search as a POST request for example.
See here for more info.