0

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")
2
  • post your code for signin and login...
    – UpAndAdam
    Commented Dec 14, 2023 at 21:52
  • @UpAndAdam i added register and login python code. Do you wanna see the html too? There isnt actually /signin code, but in all the other checks /signin didnt create problems
    – Xenoshell
    Commented Dec 14, 2023 at 23:07

1 Answer 1

1

The problem with my code was that i was using the Names of the stocks after using lookup and not the Symbols. I thought that the Names and Symbols were the same since in the finance.cs50 website they actually were the same. After changing that and integrating it into the database tables everything worked :)

4
  • mark your answer as accepted and even better if you can show the lines of code you actually changed. great that you solved it!
    – UpAndAdam
    Commented Dec 16, 2023 at 20:09
  • i asked in the discord and someone told me that the names and symbols are not interchangable. It looked like they were from the finance.cs50 website
    – Xenoshell
    Commented Dec 17, 2023 at 21:56
  • Again great job solving the problem. I am doing this one currently and that change in behavior from lookup is confusing. It would really enhance your answer if you included the exact line of code that you need to change so as to help others in kind.
    – UpAndAdam
    Commented Dec 18, 2023 at 15:18
  • @UpAndAdam that is true that showing the code would be better. Now its been a while. I looked at my code just now to see if i could find a line, but tbh there were so many lines i changed (i think). I just used symbol for every instead of names for alot of the functions and it worked out. Sorry that i cant give an exact line of code. I think it would be alot and not very instructive
    – Xenoshell
    Commented Mar 13 at 15:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .