Sending HTML form input to python script - python

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.

Related

How can I use and call a python function within HTML while using Flask?

I am new to Flask and even though I have read through the documentation, I am still very confused on the relationship between Python functions and HTML. Specifically, I am unsure of how a function can be called within an HTML page. For example, I have the following code on my route.py file:
from flask import Flask, render_template
import requests
app = Flask(__name__)
#app.route('/placement_debugger')
def placementDebugger():
return render_template('placement_debugger.html')
def get_data():
return requests.get('http://example.com'+placementID).content
Here is the code from my "placement_debugger.html" file. Basically, I am trying to obtain an ID from a user and use that ID within an HTTP GET request:
<p1>
<form action="/action_page.php">
<strong>Placement ID: </strong><input type="text" name="Placement ID"
value=""><br>
<input type="submit" value="Submit">
</form>
</p1>
How can I call my "get_data()" function within the "placement_debugger.html" page?
You can use request to get the data from your HTML inputs.
First import it from flask
from flask import request
By default Flask only allows GET requests. You'll need to allow POST methods to your route.
#app.route('/placement_debugger', methods=['GET', 'POST')
Here is how you can get the data from the HMTL form. (This would go in your get_data() function)
if request.form:
placement_id = request.form.get('Placement ID')

In Flask, how can I generate a dynamic URL upon button click?

For example, now if I have two buttons in a form element, when you click on either one of them, you'll be directed to the corresponding profile.
<form action="{{ url_for('getProfile') }}" method="post">
<button type="submit" name="submit" value="profile1"> View Profile</button>
<button type="submit" name="submit" value="profile2"> View Profile</button>
</form>
In my apprunner.py, I have
#app.route('/profile', methods=['POST'])
def getProfile():
if request.form['submit'] = 'profile1':
return render_template("profile1.html")
else if request.form['submit'] = 'profile2':
return render_template("profile2.html")
However, my problem is when I click on either button, the url will always be something like "127.0.0.1:5000/profile". But, I want it to look like "http://127.0.0.1:5000/profile1" or "http://127.0.0.1:5000/profile2".
I have looked for solution on how to generate dynamic URL online, but none of them works for button click.
Thanks in advance!
#app.route('/profile<int:user>')
def profile(user):
print(user)
You can test it on a REPL:
import flask
app = flask.Flask(__name__)
#app.route('/profile<int:user>')
def profile(user):
print(user)
ctx = app.test_request_context()
ctx.push()
flask.url_for('.profile', user=1)
'/profile1'
EDIT:
how you pass the user parameter to your new route depends on what you need. If you need hardcoded routes for profile1 and profile2 you can pass user=1 and user=2 respectively. If you want to generate those links programatically, depends on how these profiles are stored.
Otherwise you could redirect instead of render_template, to the url_for with the parsed element in the request object. This means having two routes
#app.route('/profile<int:user>')
def profile_pretty(user):
print(user)
#app.route('/profile', methods=['POST'])
def getProfile():
if request.form['submit'] = 'profile1':
return redirect(url_for('.profile_pretty', user=1))
else if request.form['submit'] = 'profile2':
return redirect(url_for('.profile_pretty', user=2))
caveat: This would make your routes look like you want, but this is inefficient as it generates a new request each time, just to make your urls the way you want. At this point it's safe to ask why do you want to have dynamically generated routes for static content.
As explained in http://exploreflask.com/en/latest/views.html#url-converters
When you define a route in Flask, you can specify parts of it that will be converted into Python variables and passed to the view function.
#app.route('/user/<username>')
def profile(username):
pass
Whatever is in the part of the URL labeled will get passed to the view as the username argument. You can also specify a converter to filter the variable before it’s passed to the view.
#app.route('/user/id/<int:user_id>')
def profile(user_id):
pass
In this code block, the URL http://myapp.com/user/id/Q29kZUxlc3NvbiEh will return a 404 status code – not found. This is because the part of the URL that is supposed to be an integer is actually a string.
We could have a second view that looks for a string as well. That would be called for /user/id/Q29kZUxlc3NvbiEh/ while the first would be called for /user/id/124.

Grab and manipulate user data without models

I'm not sure if this is even possible, but I would like to grab a user's input, pull it into my views.py, manipulate it, and then use that data in other views.
I do not need this data stored in a database, as I won't be referencing it again, and I want to keep this as lightweight as possible.
Currently, I'm trying to pull data from espn's fantasy football site using the python library espnff. My homepage consists of a textfield box and a submit button (Think of google.com).
I have functions set up that will comb through an espn url such as http://games.espn.com/ffl/clubhouse?leagueId=123456 to grab the leagueID, from there I make use of espnff to grab more info on that league.
My ideal use case is someone comes to my site, copies and pastes their league url like the one above, clicks submit and then brings them to https://example.com/{{ leagueID}/ which will display different info that I gather.
I have not found a way to do this without submitting the user input to a model. Is possible to avoid using the database? If so how?
Not sure I understood it right, but what you are trying to do can easily be done without using any models/database or any other kind of persistent storage.
The user submits that information using the form, you grab the URL from the request object in your view, parse the URL to get the league_id and then redirect the user to /{league_id}.
Then on that view, you gather the league_id parameter (from the url), use the library (espnff) to fetch the data with that id and then render the template with that data.
For example, the implementation would be something in these lines:
Make a form in your html template:
<form method="post" action="/">
{% csrf_token %}
<input type="text" name="league_url"/>
<input type="submit" value="Submit" />
</form>
in urls.py:
url(r'^$', index_view, name="index"),
url(r'^(?P<league_id>[0-9]+)$', league_view, name="league_view")
in views.py:
def index_view(request):
if request.method == 'POST':
league_url = request.POST.get('league_url', None)
# Your code to parse the URL and extract the ID
return HttpResponseRedirect('/{}'.format(league_id))
else:
# render form template
def league_view(request, league_id):
# your code here using the league_id
# and render the page with data
(I didn't tested that code, I just wrote it quickly as an example of the flow)
The django documentation describes quite extensively how to do caching with django. You can find the documentation on how to set that up here
Once it's been set up you simply use the cache in the following way
from django.core.cache import cache
cache.set('my_key', 'my_value', 60) # number is in seconds
value = cache.get('my_key')
You can provide dictionaries and such as values. The caching framework will serialize that for you using pickle.

Issues sending and receiving a GET request using Flask

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.

How to use delete() method in Google App Engine Python's request handler

In GAE Python, I could use
class MyRequestHandler(webapp.RequestHandler):
def get(self):
pass #Do Something...
def post(self):
pass #Do Something...
To handle GET and POST request. But how can I handle DELETE and PUT? I see delete() and put() in API documentation, but I don't know how to write a form to simulate DELETE and PUT.
I know in Rails, I can use post method with a hidden field in form to simulate the requests like this:
<input type="hidden" name="_method" value="delete" />
and Rails handles the dirty works automatically.
Is there any similar way to do it in GAE python?
I searched this in Google, but no luck.
Thanks.
You can use the request method which accepts all the methods like get,post,delete and put.
Then you can check it for the request type accordingly.
Check this:
http://gdata-python-client.googlecode.com/svn/trunk/pydocs/gdata.urlfetch.html
<form method="post" action="">
<input type="hidden" name="_method" value="put" />
<input type="text" name="name" value="" />
<input type="submit" value="Save" />
</form>
def post(self):
method= self.request.get("_method")
if method == 'put':
#call put() function as required
you can go through this as well for the put specification.
http://code.google.com/appengine/docs/python/tools/webapp/requesthandlerclass.html#RequestHandler_put
The HTML specification doesn't allow a form to use the DELETE method, and you probably can't get a browser to send an HTTP DELETE request with a form. The delete() method of a RequestHandler subclass would generally be used for a RESTful web application with a client that knows how to send DELETE requests, rather than using ordinary HTML forms. (For a browser-based client, you can send DELETE requests in javascript using XMLHttpRequest.)
You can implement this simulation yourself of course, In pseudo code (I'm not familiar with GAE specifics):
def post(self):
if request.get('_method', '') == 'delete':
return self.post()
If you want to truely test PUT and DELETE you will have to find a way to actually use these methods in stead of simulating them. You can use curl for this, for example, i.e.
$ curl -X DELETE url
$ curl -T file url # for PUT
See the curl documentation / manpage for more information.
First, you need to create a new RequestHandler subclass :
from google.appengine.ext import webapp
class RESTfulHandler(webapp.RequestHandler):
def post(self, *args):
method = self.request.get('_method')
if method == "put":
self.put(*args)
elif method == "delete":
self.delete(*args)
else:
self.error(405) # Method not allowed
Then your handler will inherit from it :
class MyHandler(RESTfulHandler):
def get(self):
...
def delete(self):
...
def put(self):
...
def post(self):
...
Here is another example using the X-HTTP-Method-Override header used by most JavaScript libraries :
http://github.com/sork/webapp-handlers/blob/master/restful.py

Categories