I am making a stock application, where, after a user types in a stock such as MSFT, they are redirected to .../stock?s=MSFT I have successfully made this part, but now I need Python to grab this current, unique URL so that I can parse the quote (in this case, the MSFT) out if it and save it as a new variable.
The easiest way I can think of is just to get the current URL, although I cannot seem to find a way to do this; using self.request... but this returned the error:
NameError: global name 'self' is not defined
The other ideas I came across was to use a form of urllib as it contains a specific .request_qs() method, although this requires me to pass the URL as a parameter, which should be unique every time because of the change in stock.
Here is the Python I currently have:
#app.route('/', methods=['GET', 'POST'])
def home_search():
if request.method == 'POST':
st = request.form['s']
return redirect(url_for('stock')+'?s='+st)
return render_template('stk.html')
#app.route('/stock', methods=['GET', 'POST'])
def stock():
#here I need to save the variable 'name' as the current URL. I can parse it later.
url="http://finance.yahoo.com/d/quotes.csv?s="+name"&f=snl1"
text=urllib2.urlopen(url).read()
return render_template('stock.html')
Many thanks in advance.
It's request (imported from the flask package), not self.request
The Flask docs have, as always, thorough documentation about variables in the URL: http://flask.pocoo.org/docs/quickstart/#variable-rules
#app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
On that occasion, you should read the whole Quickstart from the Flask docs: http://flask.pocoo.org/docs/quickstart/
You haven't posted any info on where the error occurs :) And I can't see where you're trying to access self.requests.
Looking at other Flask apps, it seems you should just access request instead.
Take a look at these examples: https://github.com/mitsuhiko/flask/tree/master/examples
Related
I am trying to save objects made available by the request.headers in my Flask app.
I want to render my index.html upon page load, but I also want to grab the visiting user's email so I can use it for other functions / processes.
# routes
#app.route('/')
def index():
return render_template('index.html')
def find_aad():
aad_email = request.headers.get('X-MS-CLIENT-PRINCIPAL-NAME') # aad email
return aad_email
If I try to run find_aad() on its own,
user_email = find_aad() # cant run
I will get the typical error: Working outside of request context.
How can I on an initial load of the website secure these headers and save them to an object without having these errors?
You could get at it this way, perhaps:
On that first call to index, you can create a UUID for the "session" and use that as an identifier for the user, then you pass that code back inside the rendered UI elements for stashing on the client-side. Then, on every subsequent call to the backend, you send that UUID with the rest of the request.
On those subsequent requests, you can access the email value via that UUID as the key to the data structure you're using to store client information on the backend.
This concept is the idea of a "session" with a "session id" that is common in client/server communications. Using sockets or possibly even built in or supplemental libraries for Flask would probably be a good idea instead of "rolling your own". Sorry if I'm being unhelpful or stupid - it's late where I'm at.
EDIT:
By request here's some simple pseudocode for this:
from flask import Flask
import uuid
...
uuid_to_email = {}
...
#app.route('/')
def index():
user_id = str(uuid.uuid4())
uuid_to_email[user_id] = request.headers.get('X-MS-CLIENT-PRINCIPAL-NAME')
return render_template('index.html', uuid=user_id) # where it is implied that you would then use the uuid in the client-side code to story it and pass it back to the endpoints you want to do that with
I need to be able to access an object from one route in other routes. If I only need textual data, using session variables work just fine, but what if I want to be able to access an "unjasonyfyble" object?
I managed to do it with GLOBAL VARIABLES, I just don't know if this is a good practice...
Below is the code snippet where I got it working, but please, I'd like a general case opinion.
The route:
#main.route('/start', methods=['GET', 'POST'])
def start():
global my_form
my_form = Form()
The form class
class Form(FlaskForm):
data = IntegerField('Data', validators=[DataRequired()])
submit = SubmitField('Next')
and then, on any other function, I just access my_form.data.data
I'd really like to do this the right way.
I have a problem getting data from a form using it in a route
forms.py
class Calculator(Form):
amount = IntegerField('Amount')
weight = IntegerField('Weight')
class Program(Form):
cycles = IntegerField('Cycles')
volume = FormField(Calculator)
app.py
#app.route('/', methods=('GET', 'POST'))
def index():
form = forms.Program()
if form.validate_on_submit():
values = models.Progression(
cycles=form.cycles.data,
amount=form.amount.data,
weight=form.weight.data
)
return render_template('index.html', form=form, values=values)
The data for cycles comes through just fine but I am unsure of the syntax for how to access the encapsulated form within my route. The docs say FormField will return the data dict of the enclosed form but I can't seem to figure out how to grab that and put it in a variable.
I was able to grab the data I needed using
amount=form.volume.amount.data,
weight=form.volume.weight.data
The real issue came from the fact that the form was not validating when I was using FormField. A rookie error I should have checked earlier.
I had to enable CSRF protection by importing it from flask_wtf and using CsrfProtect(app)
The problem is that the form data does not come through as the attributes of the Calculator class. The data is sent as a dictionary from the volume attribute.
Test it out with: print form.volume.data
(I suggest commenting out your values object and just use print statements)
The output should be: {'amount': foo, 'weight': bar}
Thanks for teaching me something! I never knew of FormField.
I have written a code for a sign-up page asking for information like username, password and email. After the user gives correct input, the page is redirected to
'/welcome?username=name'
I am using the self.redirect. By using the methd redirect, I am getting the the new URL as '/welcome'. How will I include the query parameter? I also want the user_name to be displayed to the redirected page like :
Welcome name
How will I do this?
This is the class I have written to handle '/welcome'
class welcomeHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write("Welcome")
app = webapp2.WSGIApplication([
('/', MainHandler),('/welcome',welcomeHandler)], debug=True)
If you need to encode it, you can use this:
import urllib
self.redirect('/welcome?' + urllib.urlencode({'username': name})
If you ever need to add more query parameters, just add them to the dictionary, as shown in How to urlencode a querystring in Python?.
You need to use string substitution. Suppose you are storing the username in name. Thus you need to write :
self.redirect("/Welcome/username="+name)
Why would you want to handle the user greeting like that? Either pass it as a template variable or do it as following:
class welcomeHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write("Welcome %s") % username
Also, make sure you create a session for the user once they've signed up, otherwise you're just creating their credential but not actually logging them in.
Suppose the following route which accesses an xml file to replace the text of a specific tag with a given xpath (?key=):
#app.route('/resource', methods = ['POST'])
def update_text():
# CODE
Then, I would use cURL like this:
curl -X POST http://ip:5000/resource?key=listOfUsers/user1 -d "John"
The xpath expreesion listOfUsers/user1 should access the tag <user1> to change its current text to "John".
I have no idea on how to achieve this because I'm just starting to learn Flask and REST and I can't find any good example for this specific case. Also, I'd like to use lxml to manipulate the xml file since I already know it.
Could somebody help and provide an example to guide me?
Before actually answering your question:
Parameters in a URL (e.g. key=listOfUsers/user1) are GET parameters and you shouldn't be using them for POST requests. A quick explanation of the difference between GET and POST can be found here.
In your case, to make use of REST principles, you should probably have:
http://ip:5000/users
http://ip:5000/users/<user_id>
Then, on each URL, you can define the behaviour of different HTTP methods (GET, POST, PUT, DELETE). For example, on /users/<user_id>, you want the following:
GET /users/<user_id> - return the information for <user_id>
POST /users/<user_id> - modify/update the information for <user_id> by providing the data
PUT - I will omit this for now as it is similar enough to `POST` at this level of depth
DELETE /users/<user_id> - delete user with ID <user_id>
So, in your example, you want do a POST to /users/user_1 with the POST data being "John". Then the XPath expression or whatever other way you want to access your data should be hidden from the user and not tightly couple to the URL. This way, if you decide to change the way you store and access data, instead of all your URL's changing, you will simply have to change the code on the server-side.
Now, the answer to your question:
Below is a basic semi-pseudocode of how you can achieve what I mentioned above:
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/users/<user_id>', methods = ['GET', 'POST', 'DELETE'])
def user(user_id):
if request.method == 'GET':
"""return the information for <user_id>"""
.
.
.
if request.method == 'POST':
"""modify/update the information for <user_id>"""
# you can use <user_id>, which is a str but could
# changed to be int or whatever you want, along
# with your lxml knowledge to make the required
# changes
data = request.form # a multidict containing POST data
.
.
.
if request.method == 'DELETE':
"""delete user with ID <user_id>"""
.
.
.
else:
# POST Error 405 Method Not Allowed
.
.
.
There are a lot of other things to consider like the POST request content-type but I think what I've said so far should be a reasonable starting point. I know I haven't directly answered the exact question you were asking but I hope this helps you. I will make some edits/additions later as well.
Let me know if I have gotten something wrong.
Here is the example in which you can easily find the way to use Post,GET method and use the same way to add other curd operations as well..
#libraries to include
import os
from flask import request, jsonify
from app import app, mongo
import logger
ROOT_PATH = os.environ.get('ROOT_PATH')<br>
#app.route('/get/questions/', methods=['GET', 'POST','DELETE', 'PATCH'])
def question():
# request.args is to get urls arguments
if request.method == 'GET':
start = request.args.get('start', default=0, type=int)
limit_url = request.args.get('limit', default=20, type=int)
questions = mongo.db.questions.find().limit(limit_url).skip(start);
data = [doc for doc in questions]
return jsonify(isError= False,
message= "Success",
statusCode= 200,
data= data), 200
# request.form to get form parameter
if request.method == 'POST':
average_time = request.form.get('average_time')
choices = request.form.get('choices')
created_by = request.form.get('created_by')
difficulty_level = request.form.get('difficulty_level')
question = request.form.get('question')
topics = request.form.get('topics')
##Do something like insert in DB or Render somewhere etc. it's up to you....... :)