I'm working on a simple UI to start and stop games by ID. The basic HTML I have written is as follows (game_id is populated by JS):
<div align="center" class="top">
<div align="left" class="game-id-input">
Game ID: <input type="text" name="game_id" id="game_id">
</div>
<div align="right" class="buttons">
<form action="{{ url_for('start_game', game_id=game_id) }}" method="get">
<input type="submit" name="start" value="Start game" class="btn btn-success"></input>
</form>
<form action="{{ url_for('end_game', game_id=game_id) }}" method="get">
<input type="submit" name="end" value="End game" class="btn btn-danger"></input>
</form>
</div>
</div>
which looks like
I also have Flask route functions defined for each of the forms:
#app.route("/start_game/<game_id>")
def start_game(game_id):
# ...
#app.route("/end_game/<game_id>")
def end_game(game_id):
# ...
In my forms, how can I make game_id correspond to the game_id from #game_id?
Currently when I submit start and end games, I get a File Not Found error because it's just appending the literal <game_id> to the route.
I'm new to web development. This should be trivial, but I don't know what to search for. Sorry in advance for such a simple question.
You are trying to generate a url based on user input, but user input isn't available when Jinja is rendering the template on the server side, it's only available on the client side. So if you wanted to post to URLs with the game id as a URL parameter, you would have to build that URL on the client side with JavaScript.
For what you're trying to do, that's not really necessary. You can get the submitted value of a named input with request.form['name']. Buttons are just like any other input, so you can name them to find out what action was taken.
#app.route('/manage_game', methods=['POST'])
def manage_game():
start = request.form['action'] == 'Start'
game_id = request.form['game_id']
if start:
start_game(game_id)
else:
stop_game(game_id)
return redirect(url_for('index'))
<form method="POST" action="{{ url_for('manage_game') }}">
<input type="text" name="game_id"/>
<input type="submit" name="action" value="Start"/>
<input type="submit" name="action" value="Stop"/>
</form>
Even that's more verbose than you need. Given that you'd know if a game was already in progress, just toggle the current status instead of picking an action. It would never make sense to start a game that's already started, only stop it.
I cannot comment, but I would like to correct davidism's code.
I believe that you need action within your form element with a value which corresponds to the function within the server python code for this to work. Minor, but an important correction. So it would be like this:
In your server.py:
#app.route('/manage_game', methods=['POST'])
def manage_game():
start = request.form['action'] == 'Start'
game_id = request.form['game_id']
if start:
start_game(game_id)
else:
stop_game(game_id)
return redirect(url_for('index'))
In your HTML:
<form method="POST" action=/manage_game>
<input type="text" name="game_id"/>
<input type="submit" name="action" value="Start"/>
<input type="submit" name="action" value="Stop"/>
</form>
Related
I have a from with three possible inputs to submit and send through a seperate script that then generates JSON data.
The problem is however while two inputs are actual inputs = one email and one being a nummer. The third one is not a really traditional input.
<form action="{ url_for('handle_data') }}" method="POST">
<div class="form-group">
<label for="Speryear">SPER jaar</label>
<input class="form-control" type="number" value="2" name="Speryear" min=0 max=10 />
</div>
<div class="form-group">
<div class="form-group">
<label for="inputEmail">Verzendings mail</label>
<input class="form-control" type="email" name="inputEmail" required />
</div>
</div>
<div class="form-group">
<div class="url-panel">
<p> <b>Url:</b></p>
<p id="api-url" name="api-url"></p>
</div>
</div>
<button id="search" type="submit" class="btn-primary">
Aanvraag indienen</button>
</form>
#app.route('/handle_data', methods=['POST'])
def handle_data():
sper_year = request.form["Speryear"]
email = request.form["inputEmail"]
url = request.form["api-url"]
Requested_data = GIPOD_converter.main(url, sper_year, email)
return Requested_data
The third input is actually a paragraph which is dynamically based on the values of a second form (the primary from) for the data requests. According to this post here:
Sending data from a html non-input to Flask
HTML forms only send along tagged values to the remote endpoint when a "submit" input is pressed.
I have tried to make this paragraph a data input but the thing is this will break the javascript I have for that specific id. Aka a the URL part that I want cannot be generated in the input field. So can my code get the paragraph from this?
Edits done as per answer.
I think you should end the app route with:
return Requested_data
Also, you do not define correctly to the url form, i.e.:
url = request.form["api-url"]
<form action="/" method="post">
<button class="btn btn-outline-primary btn-sm" type="submit" name="submit_btn" value="favorites" data-
value="{{[i]}}">Favorites</button>
</form>
I have this button in Html, I want to obtain the variable "i" which is contained in the "data-value", to use it in Python, I'm using Flask also, thanks!.
The server (Flask/Python) won't have access to the data-value attribute when you submit the form. It's not part of the data that gets sent to the server.
You might try adding a "hidden" form element, which will send a key/value pair to the server without displaying anything to the user:
<form action="/" method="post">
<input type="hidden" name="value" value="{{[i]}}">
<button class="btn btn-outline-primary btn-sm" type="submit" name="submit_btn" value="favorites" data-value="{{[i]}}">Favorites</button>
</form>
As you can see, you can retain the data-value attribute on the button, but it's not doing anything so only keep it if you're using it in Javascript somehow.
Also note that {{[i]}} will output the string representation of an array with one value, i. So the value you will get on the server is "[5]" if i is 5 for instance. If you want an actual array on the server, there are other ways to do that.
This question already has answers here:
Post values from an HTML form and access them in a Flask view
(2 answers)
Closed 2 years ago.
I am trying to implement a basic search bar functionality to my site.
I will process the actual search on my database later but at the moment I am trying to just send the request, which will simply be a string from my search bar to my search route.
I have my search bar form:
<form class="form-inline" action="{{ url_for('search') }}">
<input class="form-control" type="search" placeholder="Search">
<button class="btn btn-primary" type="submit">Search!</button>
</form>
and my route
#app.route('/search', methods=['GET', 'POST'])
def search():
user_search = request.args['search']
return render_template('results.html', search=user_search)
When I use my search bar I get the following error:
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'search'
I do not understand where I am going wrong.
That's because the request does not have "search" args. This can fix your problem:
<form class="form-inline" action="{{ url_for('search') }}">
<input class="form-control" name="search" type="search" placeholder="Search">
<button class="btn btn-primary" type="submit">Search!</button>
</form>
I added name "search" in the input.
Add the name attribute on the field to be able to access it as request.args['search'].
<input class="form-control" type="search" placeholder="Search" name="search">
Briefly, python Flask is the workbench of web hosting I use, and I am trying to create an input form that doesn't appear in your history.
This is my form html:
<form name="ViewWindow" action="/home/ViewWindow/ViewWindowResult/">
<input name="url" type="url" required="required" placeholder="URL Here">
<input type="submit" value="Go">
</form>
And this is the python code working with the input url:
#web_site.route('/home/ViewWindow/ViewWindowResult/', methods=('GET', 'POST'))
def ViewWindowResult():
urlboi = request.values.get('url')
response = urllibrequest.urlopen(url) # import urllib.request as urllibrequest
htmlBytes = response.read()
htmlstr = htmlBytes.decode("utf8")
return html("ViewWindowResult.html", value=htmlstr)
My goal is to get here; /home/ViewWindow/ViewWindow/ViewWindowResult/,
but I end up getting here when I input "https://www.w3schools.com/tags/"; /home/ViewWindow/ViewWindowResult/?url=https%3A%2F%2Fwww.w3schools.com%2Ftags%2F
Why does Flask put my inputs in the url string? I do not intend to do this anywhere.
Edit: You can check this out by going to https://sm--supermechm500.repl.co/home/ViewWindow/
Try specifying the form method like so:
<form name="ViewWindow" action="/home/ViewWindow/ViewWindowResult/" method="post">
<input name="url" type="url" required="required" placeholder="URL Here">
<input type="submit" value="Go">
</form>
use post method like
<form name="ViewWindow" action="/home/ViewWindow/ViewWindowResult/" method="post">
<input name="url" type="url" required="required" placeholder="URL Here">
<input type="submit" value="Go">
</form
and then you python code is
#web_site.route('/home/ViewWindow/ViewWindowResult/', methods=('GET', 'POST'))
def ViewWindowResult():
input=request.form['url']
#write your code here
return(input)
its working for me it will print the url which same you entered
So, I did some benchmarks to see how many requests the app could handle. It turns out that when a database operation is involved, no more than 500-560 requests/sec can be handled before timing out subsequent requests, whereas without the database layer it easily comes to a whopping 1000-1100 requests/sec.
I still didn't manage to cut the db costs in most of the pages (and I'm working on it), but there's one where this overhead can be cut: the edit page.
I have the following view which is executed when you visit http://website.com/edit. What it does is get the id parameter in the url and find the post from the db (MongoDB) with it, which then pass the iterated output to the template:
def edit(id):
item = mongo.db.documents.find_one({'_id': id})
doc = item.iteritems()
return render_template('edit.html',
content=item[0],
title=item[3],
url=item[2],
id=post[1]
)
This code is executed when you click edit in the item page, which is made like this:
{% block body %}
{{ title }}
<p>{{ content }}</p>
<div>
<a href=delete>Delete</a>
<a href=edit>Edit</a>
</div>
<form method="post" action="/post">
<input type="hidden" name="id" value="{{ id }}" />
<input type="hidden" name="url" value="{{ url }}" />
<input type="hidden" name="title" value="{{ title }}" />
<input type="hidden" name="content" value="{{ content }}" />
<div>
<h5>Your Name :</h5>
<input type="text" name="name" id="add_comment_author" />
</div>
<div>
<h5>Your Thought :</h5>
<textarea name="content id="add_comment_content"></textarea>
</div>
<input type="submit" value="Send" />
</form>
{% endblock %}
As you can see there are already hidden inputs with the needed value, but they're used for the comments.
Is it possible to do something like this?:
def edit(id):
#item = mongo.db.documents.find_one({'_id': id})
#doc = item.iteritems()
doc = request.get.previous()
return render_template('edit.html',
content=doc[0],
title=doc[3],
url=doc[2],
id=doc[1]
)
Alternatively would it be possible to have two POST in one page (one for sending a comment, the other for sending the values to the edit page?
Or maybe use Flash? But I suspect that's highly suboptimal and prone to bugs.
Typical solution is to use a caching layer like Flask-Cache and a memcached server to cache recently accessed data.
Having an edit form in the page is good. You can have as many forms as you want. Btw the common approach is to have only some sort of "templated" forms hidden that you'll then fill using jQuery os similar JS libraries.
In your example you're also passing the content field as hidden. Why? One might modify your source and change the content. :)