i searched around for this type of error and looked at my code, but was not able to figure it out. I had something very similar when debugging the buy function and used a similar process for the sell function but it doesnt make a difference.
I think i'm kind of blind to the problem now and i tried so many things that im out of ideas
Error Log:
sending GET request to /signin
sending POST request to /login
exception raised in application: TypeError: 'NoneType' object is not subscriptable
Apparently check50 is using something that is None and since it doesnt even get to call /sell, i think the error is in the index part, but i will post my sell code nonetheless. For me everything works, even when i create a completely new user, i can still buy and sell stocks.
My html is very similar to the one provided by cs50 so that "should" not be a problem
In index i cycle through all the stocks i have in my database. I tried as well to not return index into the render_template function if a user doesnt have stocks, since then index could be None but it did not change anything
def index():
"""Show portfolio of stocks"""
# update the current price of all the stocks for a specific user id
total_cash = 0
index = db.execute("SELECT * FROM stocks WHERE UserID = ?", session["user_id"])
for stock in index:
info = lookup(stock.get("Name"))
db.execute(
"UPDATE stocks SET CurrPrice = ?, TotalPrice = ? WHERE Name = ? AND UserID = ?",
round(float(info["price"]),2),
round(float(info["price"])*float(stock.get("Num")),2),
stock.get("Name"),
session["user_id"],
)
total_cash += round(float(info["price"])*float(stock.get("Num")),2)
# send the complete index from the current user to the index page
user = db.execute("SELECT cash FROM users WHERE id = ?", session["user_id"])
total_cash = float(total_cash) + round(float(user[0]["cash"]),2)
return render_template(
"index.html",
index=index,
user_cash=round(float(user[0]["cash"]),2),
total_cash=total_cash
)
In my sell code, i check for weird inputs, even when the html gets changed they should catch it. Then i add cash to the user, subtract the number of stocks and delete the stock if it is 0
@app.route("/sell", methods=["GET", "POST"])
@login_required
def sell():
"""Sell shares of stock"""
if request.method == "POST":
# check for errors and update users cash
# possible errors
# negative number of stocks
# user doesnt have enough stock to sell
stock = request.form.get("symbol")
number = request.form.get("shares")
try:
x = float(number)
if len(number) < 1:
return apology("Enter valid number of shares")
elif int(number) < 0 or x != int(x):
return apology("Enter valid number of shares")
elif stock is None or lookup(stock) is None:
return apology("Enter valid stock symbol")
except (ValueError, TypeError):
return apology("The number of shares was non-numeric")
stock_dict = lookup(stock)
stock_num = db.execute(
"SELECT Num FROM stocks WHERE Userid = ? AND Name = ?",
session["user_id"],
stock_dict["name"],
)
if stock_num[0]["Num"] < int(number) or stock_num == None:
return apology("Not enough stocks to sell")
# update cash from user
current_cash = db.execute(
"SELECT cash FROM users WHERE id = ?", session["user_id"]
)
extra_cash = int(stock_dict["price"]) * int(number)
db.execute(
"UPDATE users SET cash = ? WHERE id = ?",
(current_cash[0]["cash"] + extra_cash),
session["user_id"],
)
# update stocks from user
current_stock = db.execute(
"SELECT Num FROM stocks WHERE UserID = ? AND Name = ?",
session["user_id"],
stock_dict["name"],
)
# if stock number is 0 delete stock from stocks
if (current_stock[0]["Num"] - int(number)) == 0:
db.execute(
"DELETE FROM stocks WHERE UserID = ? AND Name = ?",
session["user_id"],
stock_dict["name"],
)
else:
db.execute(
"UPDATE stocks SET Num = ? WHERE Userid = ? AND Name = ?",
(current_stock[0]["Num"] - int(number)),
session["user_id"],
stock_dict["name"],
)
# get time and create row in history table
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
db.execute(
"INSERT INTO history (UserID, Name, Num, Price, Date) VALUES(?, ?, ?, ?, ?);",
session["user_id"],
stock_dict["name"],
int(number)*(-1),
stock_dict["price"],
dt_string,
)
return redirect("/")
else:
stocks = db.execute(
"SELECT Name FROM stocks WHERE UserID = ?", session["user_id"]
)
return render_template("sell.html", stocks=stocks)
sell.html:
{% extends "layout.html" %}
{% block title %}
Sell Stock
{% endblock %}
{% block main %}
<form action="/sell" method="POST">
<div class="mb-3">
<select class="form-select mx-auto w-auto" name="symbol">
<option disabled="" selected="">Symbol</option>
{% for stock in stocks %}
<option value="{{stock.Name}}">{{stock.Name}}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<input autocomplete="off" autofocus class="form-control mx-auto w-auto" id="shares" name="shares" placeholder="Shares" type="number" min = "0">
</div>
<button class="btn btn-primary" type="submit">Sell</button>
</form>
{% endblock %}
REGISTER:
@app.route("/register", methods=["GET", "POST"])
def register():
"""Register user"""
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
same_password = request.form.get("confirmation")
rows = db.execute("SELECT * FROM users WHERE username = ?", username)
if username is None or password is None or same_password is None:
return apology("I bet you changed the html code >-<")
elif len(username) < 1 or not username:
return apology("Username was blank")
elif len(rows) >= 1:
return apology("Username is already in use")
if len(password) < 1:
return apology("Password was blank")
elif password != same_password:
return apology("Passwords dont match")
hash = generate_password_hash(password)
db.execute("INSERT INTO users(username, hash) VALUES (?, ?);", username, hash)
return redirect("/login")
else:
return render_template("register.html")
LOGIN:
@app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
# Ensure username was submitted
if not request.form.get("username"):
return apology("must provide username", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return apology("must provide password", 403)
# Query database for username
rows = db.execute(
"SELECT * FROM users WHERE username = ?", request.form.get("username")
)
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(
rows[0]["hash"], request.form.get("password")
):
return apology("invalid username and/or password", 403)
# Remember which user has logged in
session["user_id"] = rows[0]["id"]
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
BUY:
@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
"""Buy shares of stock"""
if request.method == "POST":
stock = request.form.get("symbol")
number = request.form.get("shares")
print(f"type of number {type(number)} and num: {number}")
try:
x = float(number)
if len(number) < 1:
return apology("Enter valid number of shares")
elif int(number) < 0 or x != int(x):
return apology("Enter valid number of shares")
elif lookup(stock) is None:
return apology("Enter valid stock symbol")
except ValueError:
return apology("The number of shares was non-numeric")
stock_dict = lookup(stock)
if stock_dict is None:
return apology("Stock is not valid")
print(f"stock_dict: {stock_dict}")
price = int(stock_dict.get("price")) * int(number)
# check if user has enough cash to afford stocks
user_cash = db.execute(
"SELECT cash FROM users WHERE id = ?", session["user_id"]
)
if int(user_cash[0]["cash"]) < price:
return apology("Too broke LMAO")
else:
user_cash[0]["cash"] = user_cash[0]["cash"] - price
db.execute(
"UPDATE users SET cash = ? WHERE id = ?;",
user_cash[0]["cash"],
session["user_id"],
)
# get time and create row in history table
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
db.execute(
"INSERT INTO history (UserID, Name, Num, Price, Date) VALUES(?, ?, ?, ?, ?);",
session["user_id"],
stock_dict["name"],
int(number),
stock_dict["price"],
dt_string,
)
# check in stocks table if bought stock already exists
# if yes, update the current stock number and price per share
# if no, add it to the stocks table
stock_exists = db.execute(
"SELECT * FROM stocks WHERE Name = ? AND UserID = ?",
stock_dict["name"],
session["user_id"],
)
if len(stock_exists) == 0:
db.execute(
"INSERT INTO stocks (UserID, Name, Num, CurrPrice, TotalPrice) VALUES(?, ?, ?, ?, ?)",
session["user_id"],
stock_dict["name"],
int(number),
stock_dict["price"],
round(float(number) * stock_dict["price"],2),
)
else:
db.execute(
"UPDATE stocks SET Num = ?, CurrPrice = ?, TotalPrice = ? WHERE UserID = ? AND Name = ?",
int(stock_exists[0]["Num"]) + int(number),
round(float(stock_exists[0]["CurrPrice"]),2),
(round(float(stock_exists[0]["Num"]) + float(number),2)) * stock_dict["price"],
session["user_id"],
stock_dict["name"],
)
return render_template("buy.html",
stock = stock_dict["name"],
shares = int(number),
cash = round(float(number) * stock_dict["price"],2),
total = round(float(user_cash[0]["cash"]),2)
)
else:
return render_template("buy.html")