I'm working my way through CS50's finance problem set. (https://cs50.harvard.edu/x/2020/tracks/web/finance/)
In this task a user should be able to submit a form on a html page to request the current price of a share in a company.
Below is what I've made so far for the quote route (using python and flask):
#app.route("/quote", methods=["GET", "POST"])
#login_required
def quote():
"""Get stock quote."""
if request.method == "POST":
quote = lookup(request.form.get("requested_share"))
if quote == None:
return apology("No share found for this symbol")
return render_template("quoted.html", quote=quote)
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("quote.html")
And here is what I've written for the "quote" html page:
{% extends "layout.html" %}
{% block title %}
Quote
{% endblock %}
{% block main %}
<form action="/quote" method="post">
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="requested_share" placeholder="e.g. TSLA" type="text" />
</div>
<button class="btn btn-primary" type="submit">Request Quote</button>
</form>
{% endblock %}
Finally, here is what I've got for the "quoted" html page (where the user should be taken if their request for a quote is successful):
{% extends "layout.html" %}
{% block title %}
Quoted
{% endblock %}
{% block main %}
<p>A share of {{ quote["name"] }} costs {{ quote["price"] }}</p>
{% endblock %}
However, when I try it out, it seems to be acting as though the user hasn't typed anything in. Instead of going to the quoted.html page, it goes to the apology page from this part of the code:
if quote == None:
return apology("No share found for this symbol")
Can anyone help with this? I've been staring at it for ages, still can't see where it's going wrong. I thought it might have been something to do with the API Key, though I've followed the instructions on the page
I assumed it might have to do with the GET calls returning a None at the end
DEBUG:urllib3.connectionpool:https://cloud-sse.iexapis.com:443 "GET /stable/stock/AAPL/quote?token=[your_api_key] HTTP/1.1" 200 None
So, I've tried plugging in your code into mine and swapping out things to make sure I could recreate what you are experiencing:
if not quote:
// instead of
if quote == None:
It happened once or twice but it turned out to be wrongly entered symbols e.g. 'APPL' instead of 'AAPL' for apple stock.
I had this issue initially when nothing was being returned from the api calls through the lookup() method. If you don't see a message in your console when you lookup a stock symbol like this:
"GET /stable/stock/AAPL/quote?token=[your_api_key] HTTP/1.1" 200 None
or
"GET /stable/stock/AAPL/quote?token=[your_api_key] HTTP/1.1" 404 None
When GET returns 404 then the quote == None triggers and you get the call to the apology() function.
So if you don't see anything similar to thos lines, then that means no calls are being sent to the IEX api. I'm not sure if it's some sorta security feature (or even if that's the case, like someone else commented ensure that your api key is working properly just to be sure) but I tried making the call using the postman app by manually inserting the stock symbol and api key and after that it started working. Postman is an app for building and testing apis, you can get it here - link to Postman
This is what the result looks like in Postman:
So try that if you haven't and then checking if your console in the CS50 ide is showing the calls being made.
Related
Hi i am trying to show a message but the django message is not showing. The way i want to access this is if i send a webhook to a function in python for example. ill send a webhook post request using postman , and i will receive the message
But if i then go to my page it is not showing
so my question is why is it working when i am using postman and not when using the browser, i also have a option to send the webhook request using a form on the app itself and ive added a refresh method as well but still nothing happpens.
is there a way to get a message on django if the python function is triggered with a webhook?
i am currently using 2 methods , both are working when using postman but neither works on the app itself
method 1
messages.add_message(request, messages.INFO, 'LONG was placed.')
{% if messages %}
{% for message in messages %}
<div class = "alert alert-{{message.tags}}">{{message}}</div>
{% endfor %}
{% endif %}
and method 2
storage = messages.get_messages(request)
for message in storage:
a=(message)
print(a)
storage.used = False
context = {'a':a}
return render(request,'crodlUSDT/syntax.html',context)
and then just calling it in my base.html {{a}}
i am new to coding in general but ive been struggling for days now so would appreciate any help, thanks
use this method for views.py:
messages.info(request, "Your message")
after in HTML files:
{% if messages %}
{% for message in messages %}
<div class = "alert alert-{{message.tags}}">{{message}}</div>
{% endfor %}
{% endif %}
I am not sure if this question has been answered before, I tried to find other answers, but was unsuccessful, it may be that I am not put the right searches.
I am trying to complete the CS50 Web Finance project, and I'm running into a wall with the very beginning of the portfolio page. More specifically, I'm having trouble extracting data from my finance.db on my python page and then displaying it on my portfolio.html page. I think that I have successfully extracted the username from my finance.db, as shown in the code below.
#app.route("/")
#login_required
def index():
"""Show portfolio of stocks"""
# look up the current user
user = db.execute("SELECT username FROM users WHERE id = :id", id=session["user_id"])
return render_template("portfolio.html")
But, no matter what I do in my portfolio.html I cannot get it so say "Hello [username]" is just keeps saying "Hello undefined"
{% extends "layout.html" %}
{% block title %}
Home
{% endblock %}
{% block main %}
<p>Hello {{ [username] }}</p>
{% endblock %}
I'm sure this is something that most people are able to get, but I'm still kind of new and I just don't understand. I've tried to look up resources, but the only thing I've found is other people's code, and I don't want to copy and paste, I want to learn how to do it properly, so any help would be greatly appreciated. Thank you so much in advance.
In flask, you just need to 'pass' the username info to your portfolio.html page via render_template.
So, like:
return render_template("portfolio.html", username=user)
Then display this in the template with:
<p>Hello {{username}}</p>
EDITED. My original question wasn't clear enough. I want to allow a user to pass values into a TextField in wtforms, then the value they entered appears after they add it. This would allow the user to pass multiple values before then hitting a final "Sumbit" button on all the values that were originally entered.
I found this question for doing something with the entered text, which is what I tried.
My Python code:
from flask import Flask, request, render_template, redirect
from wtforms import TextField, Form, SubmitField
def redirect_url(default='index'):
return request.args.get('next') or \
request.referrer or \
url_for(default)
class RegionForm(Form):
field = TextField('Region')
Submit = SubmitField('AddRegion')
fieldList = []
def main():
app = Flask(__name__)
#app.route('/region/', methods=['GET'])
def region():
form = RegionForm(request.form)
return render_template("region.html",
form=form)
#app.route('/add/', methods=['POST'])
def add():
request.form['fieldList'].append(request.form['field'])
return redirect(redirect_url())
app.run(debug=True)
My html code:
<form action="/add/" method="Post">
{% for field in form %}
<tr>
<th>{{ field.label }}</th>
<td>{{ field }}</td>
</tr>
{% endfor %}
</form>
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
But after I enter the text and click the "AddRegion" button, I get the following error: The browser (or proxy) sent a request that this server could not understand. However, if I comment out the line request.form['fieldList'].append(request.form['field']), then the redirect happens, but the text hasn't been added to the hidden list on the form. How do I both add the text to the list and redirect back to the original page, so the user can add more text? It seems like there must be an error with this line only, because the rest works fine.
How can I allow a user to dynamically add text to a field, then have that field display in the browser?
Then once the complete region fields have been added, I want to be able to retrieve that list to process in a separate function later.
Part One
So after looking at your code, I think I have found your problem. Flask is very particular about its app routes.
The app route that you have in your flask is:
#app.route('/add', methods=['POST'])
However, your current action on your form which is:
<form action="/add/" method="Post">
In flask /add and /add/ are actually two different web-routes. Therefore, the #app.route is not being triggered. If you change your code to:
`<form action="/add" method="post">`
You should be good to go from here.
Part Two
I think I may have an additional issue. So within your HTML right now, you actually close your </form> tag before looping through your items in the fieldList.
</form>
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
Try:
{% for item in form.fieldList %}
{{ item }}
{% endfor %}
</form>
What I believe to be happening is that your form inputs are not actually being placed inside of the form so when you try to access them you are getting a KeyError.
I second what Cody Myers said. However there's a simple way to guarantee correct routes even if you later change them: in your form use action="{{ url_for('region') }}" and Flask will automatically substitute the correct route for the given function name.
I have a very simple app, that asks questions and moves to the next question when a question is answered correctly and send me an sms message. When it is answered incorrectly, a flashed message appears and the page reloads. I'm trying to push this on heroku but the flashed messages seem to be causing the app to crash. When the flashed messages are commented out, the app works well. When they are not, I see a 500 Internal Server Error.
Question: How can I push flashed messages when this app is deployed on heroku?
#app.route('/', methods=['GET', 'POST'])
def main():
if request.method == 'GET':
return render_template('landing.html')
elif request.form['answer'].lower() == "coffee":
message = "Step 1 completed"
server.sendmail(from_address, to_number, message)
return redirect(url_for('step_two'))
else:
message = "Sorry, that was the wrong answer. Please try again."
flash(message)
return render_template('landing.html')
The template that is rendering is extending the base and setup to show the flashed messages upon reloading.
{% extends "base.html" %}
{% block content %}
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flash style="list-style-type: none;">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
From doc
The flashing system basically makes it possible to record a message at the end of a request and access it on the next (and only the next) request
So I think you have to redirect it.
flash(message)
return redirect(url_for('main'))
Flask flash messages works with sessions.
It is just a long shot, but maybe you didn't defined the SECRET_KEY configuration, so your app is unable to set the messages to your session.
This was a templating error which could explain why I wasn't seeing any logs. Apparently class=flash isn't just for styling in this case.
I had:
<ul class=flash style="list-style-type: none;">
and it should have been:
<ul class=flashes style="list-style-type: none;">
I have a form that redirects to the same page after a user enters information (so that they can continue entering information). If the form submission is successful, I'm returning
HttpResponseRedirect(request.path)
which works fine. However, I'd also like to display some messages to the user in this case (e.g., "Your data has been saved" at the top of the screen). If I weren't redirecting, I'd just return these messages in the context dictionary. With the redirect, however, I can't do this.
So how can I pass template context information when using HttpResponseRedirect?
What I'm trying to do seems like it would be incredibly common, so please excuse me if I'm missing something obvious.
For the sake of completion and future reference, you can now use the messages framework. After you install it:
views.py
from django.contrib import messages
def view(request):
# your code
messages.success(request, "Your data has been saved!")
HttpResponseRedirect(request.path)
template.html
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
if you are using auth and have a logged in user you could:
http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.message_set.create
GET params are also hackable. The querystring, as mentioned in other answers, could be used.
I think the most preferred way would be to use the sessions framework. That way you can load up whatever you want in the context and get
{{ request.session.foo }}
foo could be the message or you could do:
{% ifequal request.session.foo 1 %} Nice work! {% else %} Almost! {% endifequal %}
and other fun stuff.
http://docs.djangoproject.com/en/dev/topics/http/sessions/#using-sessions-in-views
You can't. HttpResponseRedirect sends a client-side redirect (HTTP status code 302) to the browser, and then the browser re-requests another page.
You can set a URL query string on the redirect, though that will be visible to the user and anyone intercepting HTTP requests (i.e. proxies), and is therefore not suitable for sensitive information.
The best way would probably be to use a coded querystring on the redirect URL... its an old school approach.
You could do something like
/page/?m=1, /page/?m=2, etc
You would then parse that variable with request.GET in the view code and show the appropriate message.
From your views.py you hast have to put a key/value-pair into the session and then read it from the HTML template.
For example:
views.py
# your code here
request.session['vote'] = 1
return HttpResponseRedirect(request.path)
your_template.html
{% ifequal request.session.vote 1 %}
<!-- Your action here -->
{% endifequal %}
The only way I know of to pass any data with a redirect is to add GET parameters to the URL you're passing in. To avoid XSS hacks you'd want to pass a specific constant like:
[current path you're passing in]?message=saved
And then process the message=saved parameter in the handler for the path you passed in.
A somewhat more complicated way would be not passing the data in the redirect, and instead using something like http://code.google.com/p/django-notify/ to store session-based data that is displayed to the user following the redirect.
You add ?saved=1 to the query string and check for it with something like:
saved = request.GET.get('saved', False)