0

I have tried using dot notation in the index.html for loop. I referred to Lab 9 to check my syntax and ensure that I am passing variables correctly from app.py. I have also used flash(stock_rows[0]["symbol"]) to see that my database query can be parsed correctly.

I get the following error when accessing the "/" route: jinja2.exceptions.UndefinedError: 'row' is undefined

Full error:

INFO: 127.0.0.1 - - [05/Dec/2022 00:43:01] "GET / HTTP/1.1" 500 -
INFO: 127.0.0.1 - - [05/Dec/2022 00:46:31] "GET /buy HTTP/1.1" 200 -
INFO: 127.0.0.1 - - [05/Dec/2022 00:46:31] "GET /static/styles.css HTTP/1.1" 200 -
INFO: SELECT symbol, SUM(shares) as total_shares, price FROM transactions WHERE user_id = 2 GROUP BY symbol
INFO: SELECT cash FROM users WHERE id = 2
ERROR: Exception on / [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.10/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/workspaces/2197595/finance/helpers.py", line 34, in decorated_function
    return f(*args, **kwargs)
  File "/workspaces/2197595/finance/app.py", line 56, in index
    return render_template("index.html", rows=stock_rows, cash=usd(cash), grand_total=usd(grand_total))
  File "/usr/local/lib/python3.10/site-packages/flask/templating.py", line 147, in render_template
    return _render(app, template, context)
  File "/usr/local/lib/python3.10/site-packages/flask/templating.py", line 130, in _render
    rv = template.render(context)
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/workspaces/2197595/finance/templates/index.html", line 1, in top-level template code
    {% extends "layout.html" %}
  File "/workspaces/2197595/finance/templates/layout.html", line 61, in top-level template code
    {% block main %}{% endblock %}
  File "/workspaces/2197595/finance/templates/index.html", line 23, in block 'main'
    <td>{{ row["symbol"] }}</td>
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 466, in getitem
    return obj[argument]
jinja2.exceptions.UndefinedError: 'row' is undefined

app.py:

import os

from cs50 import SQL
from flask import Flask, flash, redirect, render_template, request, session
from flask_session import Session
from tempfile import mkdtemp
from werkzeug.security import check_password_hash, generate_password_hash

from helpers import apology, login_required, lookup, usd

# Configure application
app = Flask(__name__)

# Ensure templates are auto-reloaded
app.config["TEMPLATES_AUTO_RELOAD"] = True

# Custom filter
app.jinja_env.filters["usd"] = usd

# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)

# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///finance.db")

# Make sure API key is set
if not os.environ.get("API_KEY"):
    raise RuntimeError("API_KEY not set")


@app.after_request
def after_request(response):
    """Ensure responses aren't cached"""
    response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    response.headers["Expires"] = 0
    response.headers["Pragma"] = "no-cache"
    return response


@app.route("/",)
@login_required
def index():
    """Show portfolio of stocks"""

    id = session["user_id"]
    grand_total = 0
    stock_rows = db.execute(
        "SELECT symbol, SUM(shares) as total_shares, price FROM transactions WHERE user_id = ? GROUP BY symbol", id)
    grand_total += stock_rows[0]["price"] * stock_rows[0]["total_shares"]
    cash_rows = db.execute("SELECT cash FROM users WHERE id = ?", id)
    cash = cash_rows[0]["cash"]
    grand_total += cash
    #flash(stock_rows[0]["symbol"])
    #return apology("TODO")
    return render_template("index.html", rows=stock_rows, cash=usd(cash), grand_total=usd(grand_total))

@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
    """Buy shares of stock"""

    if request.method == "POST":
        symbol = request.form.get("symbol").upper()
        shares = int(request.form.get("shares"))
        stock = lookup(symbol)
        if not symbol:
            return apology("must provide stock symbol", 403)
        elif not stock:
            return apology("stock not found", 403)
        if not shares:
            return apology("must provide number of shares", 403)
        if not shares >= 0:
            return apology("invalid number of shares", 403)
        id = session["user_id"]
        price = int(stock['price'])
        rows = db.execute("SELECT cash FROM users WHERE id = ?", id)
        cash = rows[0]["cash"]
        total = price * shares
        if total >= cash:
            return apology("not enough cash", 403)
        else:
            db.execute("UPDATE users SET cash = ? WHERE id = ?",
                       cash - total, id)
            db.execute("INSERT INTO transactions (user_id, symbol, price, shares, total, time) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)", id, symbol, price, shares, total)
            flash("Stock Purchased!")
        return redirect("/")
    else:
        return render_template("buy.html")


@app.route("/history")
@login_required
def history():
    """Show history of transactions"""
    return apology("TODO")


@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"]

        # Success!
        flash("Logged In!")

        # 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")


@app.route("/logout")
def logout():
    """Log user out"""

    # Forget any user_id
    session.clear()

    # Redirect user to login form
    return redirect("/")


@app.route("/quote", methods=["GET", "POST"])
@login_required
def quote():
    """Get stock quote."""

    if request.method == "POST":
        symbol = request.form.get("symbol").upper()
        # Ensure stock symbol was submitted
        if not symbol:
            return apology("must provide stock symbol", 403)
        # Pull stock data using lookup()
        else:
            stock = lookup(symbol)
            return render_template("quoted.html", stock={'name': stock['name'], 'symbol': stock['symbol'], 'price': usd(stock['price'])})
    else:
        return render_template("quote.html")


@app.route("/register", methods=["GET", "POST"])
def register():
    """Register user"""

    # 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)

        # Ensure password confirmation was submitted
        elif not request.form.get("password_confirmation"):
            return apology("must provide password confirmation", 403)

        # Ensure password and confirmation match
        if request.form.get("password") != request.form.get("password_confirmation"):
            return apology("password and confirmation do not match", 403)

        # Register user if username does not exist
        try:
            registrant = db.execute("INSERT INTO users (username, hash) VALUES (?, ?)", request.form.get(
                "username"), generate_password_hash(request.form.get("password")))
        except:
            return apology("username taken", 403)

        # Remember which user has logged in
        session["user_id"] = request.form.get("username")

        # Success!
        flash("Registered!")

        # Redirect user to home page
        return redirect("/")

    # User reached route via GET (as by clicking a link or via redirect)
    else:
        return render_template("register.html")


@app.route("/sell", methods=["GET", "POST"])
@login_required
def sell():
    """Sell shares of stock"""
    return apology("TODO")

index.html:

{% extends "layout.html" %}

{% block title %}
    Portfolio
{% endblock %}

{% block main %}
<div class="section">

    <h2>Portfolio</h2>
    <table class=""table table-striped">
        <thead>
            <tr>
                <th>Symbol</th>
                <th>Shares</th>
                <th>Price</th>
                <th>Total</th>
            </tr>
        </thead>
        <tbody>
            { % for row in rows % }
            <tr>
                <td>{{ row["symbol"] }}</td>
                <td>{{ row["total_shares"] }}</td>
                <td>{{ row["price"] }}</td>
                <td>{{ row["price"] * row["total_shares"] }}</td>
            </tr>
            { % endfor % }
        </tbody>
    </table>
    <table>
        <thead>
            <th>Cash</th>
            <th>Grand Total</th>
        </thead>
        <tbody>
            <tr>
                <td>{{ cash }}</td>
                <td>{{ grand_total }}</td>
            </tr>
        </tbody>
    </table>

</div>
{% endblock %}

1 Answer 1

0

Welp... I just figured out I had an extra space within my curly braces. The table seems to be rendering fine now.

For example:

            { % for row in rows % }

...should have been:

            {% for row in rows %}

You must log in to answer this question.

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