Pass form values to the next request - python

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. :)

Related

FLASK app: Sending data from a Form through another script while one "input" is a dynamic paragraph

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"]

How to get form data from input as variable in Flask?

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>

Passing values from one html page to another via Flask (Python)

My web app currently has 3 pages. I obtained a user input on the first page, which I passed to my view.py, and calculated some variables I needed for my 2nd page. I want to pass the variables that exist in my 2nd page to the third page, but don't know how to go about it. Any suggestions on how to modify the html for the 2nd page to achieve this?
So far, I'm solving this problem by making my variables global in view.py. This seems to work but doesn't seem to be a viable long-term solution.
Thanks!
existing variables: thePrediction, theData
The html for the 2nd page:
<div class = "caption-full">
<h3>Currently, I have a {{thePercentage}} chance of getting adopted.</h3>
{% if thePrediction[1] + thePrediction[2] >0%}
<form action="/third_page" method="GET">
<button class="btn btn-large btn-info" >Go to third page</button>
</form>
{% endif %}
</div>
I think I figured it out:
<div class = "caption-full">
<h3>Currently, I have a {{thePercentage}} chance of getting adopted.</h3>
{% if thePrediction[1] + thePrediction[2] >0%}
<form action="/third_page" method="GET">
<input type="hidden" name="alignment" value="{{thePassedValue}}" />
<button class="btn btn-large btn-info" >Go to third page</button>
</form>
{% endif %}
</div>

How to render field data into a template file using django?

I am trying to render data into a template file using the following Code. The error I encounter is something like :
This page contains the following errors:
error on line 13 at column 16: AttValue: " or ' expected
Below is a rendering of the page up to the first error.
Name,Author,Status
Code
def editbook(request):
if request.method == 'GET':
name = request.GET.get('name',False)
Details = bookInfo.objects.all().filter(Name=name)
id = Details.values_list('id',flat=True)
Name = Details.values_list('Name',flat=True)
Author = Details.values_list('Author',flat=True)
Status = Details.values_list('Status',flat=True)
return render(request, 'app/add.html', {'Name' : Name, 'Author' : Author, 'Status' : Status}, content_type="application/xhtml+xml")
Template Code
<html>
<head>
<title>Add</title>
</head>
<body>
<form action="add/" method="post">
{% csrf_token %}
<p style="font-family:Courier New;color:teal">Name <input type="text" placeholder="Name of the book" name="name"></input></p>
<p style="font-family:Courier New;color:teal">Author <input type="text" placeholder="Author of the book" name="author"></input></p>
<p style="font-family:Courier New; color:teal"> Status
<select name="status">
<option value=1>Read</option>
<option value=1>Unread</option>
</select>
</p>
<input type="submit" id="booksubmit" value="Add/Edit Book"></input>
</form>
</body>
</html>
I searched through Google and I found that this somewhat like XML parsing error (Please correct me if I am wrong). Now I am stuck at this position. Please help.
EDIT Here the form for adding the book has a different method for saving the field data into database.
Your HTML is malformed for whatever type is is, html and html5.
And to be picky, your python code should be refactored as well.
Normally we define variables with lowercase letter instead of a capital so
the variables Details, Name, Author, Status should be details, name, author, status.
Further more, is your class name bookInfo spelled like that?
Classes in python should start with a capital letter so bookInfo should be BookInfo.
The proper HTML5 is this:
<html>
<head>
<title>Add</title>
</head>
<body>
<form action="add/" method="post">
{% csrf_token %}
<p style="font-family:Courier New;color:teal;">Name <input type="text" placeholder="Name of the book" name="name" /></p>
<p style="font-family:Courier New;color:teal;">Author <input type="text" placeholder="Author of the book" name="author" /></p>
<p style="font-family:Courier New; color:teal;"> Status
<select name="status">
<option value=1>Read</option>
<option value=1>Unread</option>
</select>
</p>
<input type="submit" id="booksubmit" value="Add/Edit Book" />
</form>
</body>
</html>
If you're not using HTML5 and that depends on the Doctype you've defined.
You can't use placeholders in your input fields.
The inputs need to get closed with a /> and not a </input>.
The inline styles you've provided in your html is incomplete:
style="font-family:Courier New; color:teal"
should be
style="font-family:Courier New; color:teal;"
The return you're using doesn't need a content_type you can drop that.
You're not using your template variables anywhere so that's not it but if you would like to start using them the syntax for the template language is {{ variable_name }} and in your case that would be (until you refactor)
{{ Name }}, {{ Status }} for example.
Also you're seeing this error because of the content_type since you're actively telling the browser to parse the document as xhtml+xml and that's XHTML with rules, which you're effectively breaking.
For adding the value from your Django app to your input fields do this, (without a Django Form)
<input type="text" value="{{ Name }}" />
But I would recommend using a Django Form instead.
I think you're getting this error because you're template is not 'well formed'. My guess is that there's an error in the xml that's being output.
You've declared the content type of your http response to be application/xhtml+xml. xhtml requires you to put quotes around all your attributes. You're probably missing/adding a quotation mark somewhere. I can't see from your template where that is.
Either check what your template variables ({{ Name }}, {{ Author }} and {{ Status }}) are outputting to see if they're adding in a stray quotation mark, or try changing the content type (maybe just drop the content_type parameter you're passing to the render function).

How to pass variables to a form before it is processed

I have the following template form, containing several variables.
<form action="https://me.s3.amazonaws.com/" method="post" enctype='multipart/form-data' class="upload-form">
<input type="hidden" name="key" value="videos/{{filename}}">
<input type="hidden" name="AWSAccessKeyId" value="{{access_key}}">
<input type="hidden" name="acl" value="public-read">
<input type="hidden" name="policy" value="{{policy}}">
<input type="hidden" name="signature" value="{{signature}}">
<input type="hidden" name="Content-Type" value="{{content_type}}">
<input name="file" type="file">
<input type="submit" value="Upload" name="upload">
</form>
However, as soon as the submit button is hit, the form is sent to amazon, and I'm not able to pass it variables. This is what I've been trying to do, unsuccessfully --
if 'upload' in request.POST:
policy = base64.b64encode(...)
signature = base64.b64encode(
hmac.new('secret_key', policy, sha).digest())
file = request.POST['files']
filename=file.name
content_type=mimetypes.guess_type(filename)[0]
What do I need to do to pass the variables to the form after the POST request but BEFORE amazon processes the form? Thank you.
You should change your form's action to your django view and in your view you can re-post to https://me.s3.amazonaws.com/:
In your template
<form action="http://mywebsite/upload" method="post" ...
In your view.py:
def upload(request):
# Your treatment here.
# Post the data to amazon S3.
urllib2.urlopen("https://me.s3.amazonaws.com/", your_data)
...
You could change the form to POST to one of your own views, then do your post-processing in your view, and then within your view code, issue a POST to Amazon with the correct values using, say, urllib2 or similar.

Categories