Chapter 5: Give It a Web Interface

Turning your parameterized Python report into a simple Flask app

Chapter Goal

From Command Line to Browser Form

In Chapter 4, we made the report more useful by passing parameters from the command line. That was a big improvement, but most business users do not want to run commands.

In this chapter, we move the same logic into a simple Flask web app. The user will open a browser, choose filters from a form, and see the report output on the page.

Open AppBrowser page
Enter FiltersMaterial type + plant
SubmitPOST request
Processpandas filtering
DisplayHTML table
Big idea: Flask lets you wrap your Python logic in a browser interface without jumping straight into a full enterprise app.

ABAP Selection Screen vs Flask Form

The mental model is familiar. In ABAP, the selection screen collects inputs before the report runs. In Flask, an HTML form collects inputs before the Python function processes them.

ABAP

PARAMETERS: p_mtart TYPE mtart DEFAULT 'FERT', p_plant TYPE werks_d DEFAULT '1000'. START-OF-SELECTION. SELECT matnr, maktx, mtart, plant, stock FROM zmaterial_stock INTO TABLE @DATA(lt_materials) WHERE mtart = @p_mtart AND plant = @p_plant.

Flask Form Preview

http://127.0.0.1:5000
Generate Report
Python translation: Flask gives you routes. A route is a URL that runs a Python function.

Step 1: Install Flask

Activate your virtual environment, then install Flask.

python -m pip install flask pandas openpyxl

Update your requirements.txt:

python -m pip freeze > requirements.txt

Flask is a lightweight Python web framework. It lets you define URLs, receive form input, run Python logic, and return HTML pages to the browser.

Step 2: Project Folder Structure

Flask projects can grow quickly, but we will keep this one simple.

think-like-python-flask-report/ │ ├── app.py ├── materials.csv ├── requirements.txt └── templates/ └── index.html
🐍
app.py

The Python Flask application.

📄
materials.csv

The sample material data.

🌐
templates/index.html

The browser form and report page.

Important: The folder must be named templates. Flask looks for HTML templates there by default.

Step 3: Create the Flask App

Create a file named app.py. This file will load the CSV, receive form values, filter the data, and send results to the HTML page.

from flask import Flask, render_template, request import pandas as pd app = Flask(__name__) DATA_FILE = "materials.csv" @app.route("/", methods=["GET", "POST"]) def index(): df = pd.read_csv(DATA_FILE) material_type = "FERT" plant = "1000" records = [] message = "" if request.method == "POST": material_type = request.form.get("material_type", "FERT") plant = request.form.get("plant", "1000") filtered_df = df[ (df["mtart"] == material_type) & (df["plant"].astype(str) == plant) ] filtered_df = filtered_df.sort_values(by="stock", ascending=False) if filtered_df.empty: message = "No records found for the selected filters." else: records = filtered_df.to_dict(orient="records") message = f"Found {len(records)} record(s)." return render_template( "index.html", material_type=material_type, plant=plant, records=records, message=message ) if __name__ == "__main__": app.run(debug=True)

@app.route("/") means this function runs when the user visits the home page of the app. The slash represents the root URL, like http://127.0.0.1:5000/.

request.form contains the values submitted by the HTML form. This is how the selected material type and plant get from the browser into Python.

Step 4: Create the HTML Template

Create a folder named templates, then create a file inside it named index.html.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Material Report</title> <style> body { font-family: Arial, sans-serif; background: #f4f6f8; margin: 0; padding: 30px; color: #2d3748; } .container { max-width: 950px; margin: auto; background: white; padding: 25px; border-radius: 12px; } h1 { color: #0b1f3a; } label { display: block; margin-top: 12px; font-weight: bold; } input, select { width: 100%; padding: 10px; margin-top: 4px; } button { margin-top: 18px; background: #13a89e; color: white; border: none; padding: 10px 16px; border-radius: 8px; font-weight: bold; } table { width: 100%; border-collapse: collapse; margin-top: 22px; } th, td { border: 1px solid #dbeafe; padding: 9px; text-align: left; } th { background: #e8eef7; color: #0b1f3a; } .message { margin-top: 18px; background: #ecfeff; border-left: 5px solid #06b6d4; padding: 12px; } </style> </head> <body> <div class="container"> <h1>Material Report</h1> <p>Select your filters and generate the report.</p> <form method="POST"> <label>Material Type</label> <select name="material_type"> <option value="FERT">FERT</option> <option value="HALB">HALB</option> <option value="ROH">ROH</option> <option value="HAWA">HAWA</option> </select> <label>Plant</label> <input name="plant" value="{{ plant }}"> <button type="submit">Generate Report</button> </form> {% if message %} <div class="message">{{ message }}</div> {% endif %} {% if records %} <table> <tr> <th>Material</th> <th>Description</th> <th>Type</th> <th>Plant</th> <th>Stock</th> </tr> {% for row in records %} <tr> <td>{{ row.matnr }}</td> <td>{{ row.maktx }}</td> <td>{{ row.mtart }}</td> <td>{{ row.plant }}</td> <td>{{ row.stock }}</td> </tr> {% endfor %} </table> {% endif %} </div> </body> </html>

Flask uses a template engine called Jinja. Values like {{ plant }} are replaced with Python values. Blocks like {% for row in records %} loop through data sent from app.py.

Step 5: Run the App

From the project folder, run:

python app.py

You should see output similar to this:

Terminal Preview
* Serving Flask app 'app' * Debug mode: on * Running on http://127.0.0.1:5000 Press CTRL+C to quit

Open your browser and go to:

http://127.0.0.1:5000
Local only: This runs on your machine. Other users cannot access it yet. Deployment comes later.

What You Should See

The app should show a small form. After submitting, it should show matching records.

Before Submit

Material Report
Generate Report

After Submit

Material Report Results
Found 2 record(s).
Material Description Type Plant Stock
1006Demo Finished Product 3FERT100067
1001Demo Finished ProductFERT100045

What Just Happened?

The Flask app follows a simple request-response pattern.

GETShow empty form
POSTUser submits form
FilterPython processes data
RenderTemplate receives records
ResultBrowser displays table
ABAP comparison: Think of GET as displaying the selection screen and POST as pressing execute.

Common Beginner Issues

Make sure the file is located here:

templates/index.html

The folder must be named exactly templates.

Make sure materials.csv is in the same folder as app.py.

Another app may already be running on port 5000. Stop the previous Flask app with CTRL+C, or run on another port:

app.run(debug=True, port=5001)

Try This

Add this input to the HTML form:

<label>Minimum Stock</label> <input name="min_stock" value="0">

Then read and apply it in Python:

min_stock = int(request.form.get("min_stock", 0)) filtered_df = filtered_df[ filtered_df["stock"] >= min_stock ]

Chapter 5 Checkpoint

Next: Chapter 6 should make this web app feel more like a practical reporting tool: export button, cleaner layout, and a chart on the results page.
End of Chapter 5