Past Lesson Note

This note is from 8 months ago. You're viewing content from a previous lesson.

Daily Note for September 23, 2025 Past Lesson

At the start of every class, please: 

  1. Make sure you are working from your programming folder
  2. Make sure your python virtual environment is activated
  3. Make sure you can access our test template at 127.0.0.1:5000

Big idea

Jinja is a templating language that lets you combine HTML with Python data. Flask uses Jinja to fill in placeholders in your HTML so your pages can display dynamic content (e.g., a user’s name, a list of items, a table of results).


Learning objectives (You should be able to…)

  • Define what a template is and where Flask looks for templates.

  • Construct a Flask view that passes variables to a Jinja template.

  • Apply Jinja syntax for variables {{ ... }}, conditionals {% if ... %}, and loops {% for ... %}.

  • Use common Jinja filters (e.g., |upper|length).

  • Organize templates with basic inheritance (base.html and {% block %}).


Starter project structure (Memorize this)

Create a templates/ folder in the same directory as app.py.

your-project/
├─ app.py
└─ templates/
   ├─ base.html
   ├─ hello.html
   └─ items.html

Flask automatically looks in templates/ for HTML files.


Step 1 — Minimal Flask route + Jinja variable (Construct)

1A. Create app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def home():
    # Python data you want to display in HTML:
    name = "Ada Lovelace"
    # Pass it to the template as a named variable:
    return render_template("hello.html", person=name)

if __name__ == "__main__":
    app.run(debug=True)

1B. Create templates/hello.html

<!doctype html>
<html lang="en">
  <head><meta charset="utf-8"><title>Hello</title></head>
  <body>
    <h1>Hello, {{ person }}!</h1>
    <p>This value came from Python through Flask → Jinja.</p>
  </body>
</html>

1C. Run it

  • Start the server: python app.py

  • Visit: http://127.0.0.1:5000/

  • Expected output: “Hello, Ada Lovelace!”

Key syntax:

  • {{ person }} = print the value of a variable.

  • Values come from render_template("hello.html", person=name).


Step 2 — Conditionals and loops (Apply)

2A. Update app.py with more data

@app.route("/items")
def items():
    username = "Grace"
    cart = ["notebook", "pencil", "eraser"]
    is_member = True
    return render_template("items.html", username=username, cart=cart, is_member=is_member)

2B. Create templates/items.html

<!doctype html>
<html lang="en">
  <head><meta charset="utf-8"><title>Items</title></head>
  <body>
    <h1>Welcome, {{ username }}.</h1>

    {% if is_member %}
      <p>Member discount applied.</p>
    {% else %}
      <p>No discount. <a href="#">Join now</a></p>
    {% endif %}

    <h2>Your cart ({{ cart|length }} items)</h2>
    <ul>
      {% for item in cart %}
        <li>{{ loop.index }}. {{ item|upper }}</li>
      {% endfor %}
    </ul>

    <p>First item: {{ cart[0] }}</p>
  </body>
</html>

New syntax:

  • {% if ... %} ... {% endif %} = conditional blocks.

  • {% for x in list %} ... {% endfor %} = loops.

  • {{ loop.index }} = 1-based index inside a loop.

  • |upper|length = filters that transform output before printing.


Step 3 — Template inheritance (Organize)

Goal: Put shared HTML (head, nav, footer) into base.html. Each page fills in a {% block %}.

3A. Create templates/base.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{% block title %}My Site{% endblock %}</title>
  </head>
  <body>
    <header>
      <nav>
        <a href="/">Home</a> | <a href="/items">Items</a>
      </nav>
      <hr>
    </header>

    <main>
      {% block content %}{% endblock %}
    </main>

    <hr>
    <footer>
      <small>© 2025 My Site</small>
    </footer>
  </body>
</html>

3B. Update hello.html to extend base.html

{% extends "base.html" %}

{% block title %}Hello{% endblock %}

{% block content %}
  <h1>Hello, {{ person }}!</h1>
  <p>Now using template inheritance.</p>
{% endblock %}

3C. Update items.html to extend base.html

{% extends "base.html" %}

{% block title %}Your Items{% endblock %}

{% block content %}
  <h1>Welcome, {{ username }}.</h1>

  {% if is_member %}
    <p>Member discount applied.</p>
  {% else %}
    <p>No discount. <a href="#">Join now</a></p>
  {% endif %}

  <h2>Your cart ({{ cart|length }} items)</h2>
  <ul>
    {% for item in cart %}
      <li>{{ loop.index }}. {{ item|upper }}</li>
    {% endfor %}
  </ul>
{% endblock %}

Quick reference (Remember)

  • Print variable: {{ variable }}

  • If: {% if cond %}...{% elif ... %}...{% else %}...{% endif %}

  • For: {% for x in seq %}...{{ loop.index }}...{% endfor %}

  • Filters: {{ name|upper }}{{ text|lower }}{{ items|length }}

  • Default value: {{ value|default("N/A") }}

  • Inheritance: top file uses {% block %}s; child uses {% extends "base.html" %} then fills blocks.


Common mistakes (Troubleshoot)

  1. TemplateNotFound: File not in templates/ or wrong filename.

  2. UndefinedError: You used {{ x }} but didn’t pass x in render_template.

  3. Jinja syntax error: Mismatched tags. Example: started {% if %} but forgot {% endif %}.

  4. Nothing changes on refresh: Your browser cached it. Hard refresh, or restart Flask if you edited Python.


Mini-tasks (Practice)

  1. Variables (Apply):
    Add age = 17 in / route and show: Hello, Ada Lovelace (17). Use hello.html.

  2. Conditionals (Apply):
    In /items, add total = 9.5. Show “Shipping is free” if total >= 10 else “Shipping: 3.00”.

  3. Loop + index (Apply):
    Add a list of courses = ["Math", "CS", "History"] and render them as an ordered list with index.

  4. Filter (Apply):
    Print username in title case: {{ username|title }}.

  5. Default filter (Apply):
    Try {{ nickname|default("no nickname") }} without passing nickname.

  6. Inheritance (Construct):
    Add a new page /about that extends base.html and fills both title and content blocks.


Stretch (Challenge)

  • Dictionary access: Pass user = {"first": "Grace", "last": "Hopper"} and print {{ user.first }} {{ user.last }}.

  • Loop over dict: Pass scores = {"Exam": 88, "Project": 95} and render a table of keys/values.

  • Include partials: Create templates/_message.html and include it with {% include "_message.html" %}.

<!-- templates/_message.html -->
<p><em>This is a reusable partial.</em></p>

Exit ticket (Evaluate)

Answer briefly:

  1. What is the difference between {{ ... }} and {% ... %} in Jinja?

  2. Why do we use a base.html with {% block %}s?

  3. Show one example of a Jinja filter and explain what it does.


Marking guidance (for yourself)

  • Level 3–4 (Satisfactory): Correctly passes at least one variable and displays it with {{ ... }}; uses one control structure.

  • Level 5–6 (Good): Uses variables, a loop, a conditional, and at least one filter; clean inheritance with base.html.

  • Level 7 (Excellent): Adds a new route + template that extends base.html, uses filters and defaulting, and demonstrates clear organization and comments.


Appendix: Security note (Understand)

Jinja auto-escapes variables in HTML (it converts < to &lt;, etc.). This helps prevent XSS. Only use |safe on trusted content you 100% control.

<!-- Dangerous if the content comes from users -->
{{ html_snippet|safe }}

That’s it. Build the three templates, pass some data from your Flask route, and practice with variables, loops, conditionals, and filters.