I need to save GET URI to use it later after POSTing form in Flask. The problem is, that it is overwritten when doing POST. Here is the code (schematically):
#app.route('/test', methods=['get', 'post'])
def test_view():
url_query = request.url.replace(request.base_url,'/')
form = Form()
if form.validate_on_submit():
# at this point url_query is already overriten with '/'
yadayada(url_query)
So, for example, if user requests https://host/test?kekeke=nenene
I expecting that the string "/test?kekeke=nenene" would be passed to yadayada(), but at practice it would be overwritten by '/'. How to solve that properly? Thanks.
Set your Form action to include the query parameters:
<form method="POST" action="{{ url_for('test_view', **request.args) }}">
where the request.args object gives you access to the query parameters, and the url_for() function generates a new URL with every key-value pair from request.args as query parameters.
Now when the form is POSTed the exact same query parameters are sent along as where used for the original GET request that rendered the form.
Related
#app.route('/path', methods= ['POST', 'GET'])
def path():
results = getResults(request)
return render_template('path_result.html', results=results)
I need a way to update the URL.
Currently, when the user submits their form, the results are returned and rendered, but the URL does not contain the submitted page parameters. So the url remains as /path, instead of /path?formDataA=foo
Mainly I need this to allow users to share the links to specific results with one another easily.
When you POST your data to a route you can't see the parameter. Thats the normal way. You can send your form as GET then all form parameters are appended to your url but i would prefer the POST way.
After posting the values you can redirect to another route where you display your values. When redirecting you can append some parameters your url that you need.
So make a method that process your form data. After processing redirect to another page where you display that values.
https://laravel.com/docs/8.x/routing#redirect-routes
Using url_for('search', **request.form), able to send previous form data to new page link, but unable to edit one of the hidden form parameterrequest.args.get('page') to new value (next page number).
As per my current understanding, this Stack Overflow answer suggests it is possible to update previous form values, and pass them into pagination links using url_for. But while doing so, getting error AttributeError: 'ImmutableMultiDict' object has no attribute 'page'. But request.args show some methods like add and setlist(key, new_list).
Is it possible to edit and update request.arg or request.form parameters directly and pass them to url_for() with new values, without using Session, Form Rewriting or any pagination library?
#app.route('/search', methods = ['POST', 'GET'])
def video_search():
# able to read request.args / request.form parameters here
# can we edit them ?
# error request.args.page.data += 1
# error request.form.page.data += 1
url_for('search', **request.form)
return content
This question already has answers here:
Sending data from HTML form to a Python script in Flask
(2 answers)
How to use variables in SQL statement in Python?
(5 answers)
Closed 3 years ago.
I'm trying to create a basic web app that has an HTML form on the root landing page, and then after submission, run a postgresql query with the desired input and redirect the user to a page with a generated matplotlib chart of their input. In my main function, I have the following:
#app.route('/', methods=['POST'])
def main():
return render_template("main.html")
So let's say I have my main html file being rendered by the flask app. I have another route below:
#app.route('/query', methods=['POST'])
def queryPage():
# code to execute query with information
# passed from the main.html template
# then generate chart via matplotlib via returned information
return render_template("query.html")
I'm confused as to how to get my input from the form in main.html to send information back to the application for rendering at the /query endpoint. If someone could elaborate on this, I'd appreciate it. Front end is not my strong suit. Thanks!
You need a form on main.html... maybe like this (note the form action):
<form action = /query method="POST">
<label for="username">USERNAME:</label>
<input type="text" name="username" id="username" size="15">
<input type="submit" name="submit" id="submit"/>
</form>
When that form gets sent (after a user clicks a button lets say), the route in your flask code that matches the action (/query in this case) will get called and execute. Also the name= variables in any of your form elements will be available in your request on the back end (I'm using the variable username as an example). You can get them like this: request.form['username']. Other form variables (like a check box) will be slightly different.
Anyway in your case you need a /query action in your html somewhere in main.html.... It could be called by a button or timed javascript etc...
When this /query action is called on your main.html, you need to
return render_template('query.html, username=username)
and then the username variable will be available on the query.html page.
Keep in mind I only passed a single variable. You can pass a multiple variables, lists, dictionaries etc...
Also keep in mind any variable that you return to query.html can be made extremely dynamic using Jinja templating. You can loop through lists and print different html tags etc and use logic within your html... possible depending on what the values are that get returned to the page.
If I understand your question correctly then you are having difficulty passing the form information from your main function to the separate queryPage function for rendering. This can easily be achieved by providing the values you wish to pass as keyword arguments to the url_for function. These can then be retrieved from request.args within the queryPage function. Given the fact that you are returning query.html from this function and not an image, I assume that you are intending on displaying your chart within an img tag in query.html. In this case you will need another view function to generate and return the image itself. You may also need to disable browser caching for this endpoint to prevent browsers treating your dynamic image as if it were a static image https://stackoverflow.com/a/2068407/10548137.
#app.route('/', methods=['GET', 'POST'])
def main():
form = MyForm(request.form)
if request.method == "POST" and form.validate():
return redirect(url_for("queryPage", **form.data))
return render_template("main.html", form=form)
#app.route('/query', methods=['GET'])
def queryPage():
arguments = request.args.to_dict()
image_url = url_for("make_chart", **arguments)
return render_template("query.html", image_url=image_url)
#app.route('/make_chart', methods=['GET'])
def make_chart():
arguments = request.args.to_dict()
# perform postgres query here using arguments
# generate matplotlib chart here using query results
# ? save chart in BytesIO buffer in png format
response = send_file(file_pointer, mimetype="image/png")
# just return response here if don't need to alter headers
response = make_response(response)
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "0"
return response
I have a Route named search: #app.route('/search')
Is it possible to add multiple optional parameters to it? Example:
#app.route('/search/pg/<int:pg>')
#app.route('/search/types/<types>')
#app.route('/search/number/<int:number>')
#app.route('/search/subject/<subject>')
The order in the URL shouldnt matter, so I could call /search/pg/2, or /search/subject/MySubject/pg/2 or /search/types/posts/subject/MySubject/pg/2
I tried this, but it only works with the full paths and all the parameters:
#app.route('/search/pg/<int:pg>/types/<types>/subject/<subject>', methods=['GET', 'POST'])
#app.route('/search/subject', defaults={'subject', None})
#app.route('/search/pg/<int:pg>/types/<types>', methods=['GET', 'POST'])
#app.route('/search/types', defaults={'types', None})
#app.route('/search', defaults={'pg': 1}, methods=['GET', 'POST'])
#app.route('/search/pg/<int:pg>', methods=['GET', 'POST'])
def search(pg, types=None, subject=None):
pass
You can use filter in the URL instead of "sub-resources".
Then you can put search arguments in any order in your request:
/search?pg=<pg>&types=<types>
Inside the flask view function you can retrieve parameters from the request object:
#app.route('/search/')
def search():
pg = request.args.get('pg')
...
#David, I worked on a package that does this called flask_optional_routes. The code is located at: https://github.com/sudouser2010/flask_optional_routes.
from flask import Flask
from flask_optional_routes import OptionalRoutes
app = Flask(__name__)
optional = OptionalRoutes(app)
#optional.routes('/<user_id>/<user_name>?/')
def foobar(user_id, user_name=None):
return 'it worked!'
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
If you are trying to route a user based on multiple, optional form values as route parameters, then I found a useful workaround.
First, create an intermediate route that will create the query string. This route will only allow for POST methods (since the 1 or more of the form values would be submitted by the form).
#app.route('/example', methods=['POST']
def createQueryParams():
form = ExampleForm()
# Retrieve/cleanse/validate form data
example1 = form.example_field1.data
example2 = form.example_field2.data
return redirect(url_for('app.route', example1=example1, example2=example2))
Note that each keyword argument in the redirect(url_for()) needs to either be a parameter used in app.route or something you expect to add as a query parameter.
Next, alter your app.route() to have a GET method and extract the query parameters like #lee-pai-long mentioned
#app.route('/search', methods=['GET'])
def search():
if len(request.args) > 0:
example1 = request.args.get('example1')
example2 = request.args.get('example2')
# Do stuff
Finally, in the .html template where the form is submitted, make sure the form action directs to the createQueryParams route, not the search route. Such as
<form action="{{ url_for('app.createQueryParams') }}" method="POST">
<!-- Flask form stuff -->
</form>
I used this structure to create a page where users could filter posts based on up to X different criteria (title search, date sort, tags, etc.). I wanted to be able to have an optimized query parameter, but without the intermediary createQueryParams route, I was not able to determine what form values were selected until after the url was created, since the single route owned both methods.
I'm using tornado and I want to Insert something to my MongoDB from values in a HTML form.
in the HTML file I have a form like this:
<form method="get" >
with 2 textbox and a submit button.
and I don't know what to set as "action"
I have a handler class with a function called "post" like bellow:
class MyHandler(tornado.web.RequestHandler):
def post(self):
name = self.get_argument("Name", "")
index = self.get_argument("Index","")
.... code for updating MongoDB
I have a file called BaseUrl.py that contains:
(/admin/edit[/]?',MyHandler )
but it seems that the "post" function in myHandler does not execute.
could you please give me some advice about how to properly set my URLs and form actions?
Change the form method to POST as you are handling in a POST request:
<form method="POST" >
You also need to provide an action if the form is served from different page, so your form should be:
<form method="POST" action="/admin/edit">
Your post method isn't called because your form specifies method="get". Change that to method="post" and it'll probably work.
If the action is empty the browser will submit the request to the current page, so if you have a get handler serving the form at the same URL you don't need to specify it.