Programming lesson
Building a Flask Baking Contest App: A Step-by-Step Tutorial with SQLite
Learn to create a Flask web app with SQLite for managing a baking contest. This tutorial covers user registration, validation, and result listing, perfect for COP4521 assignment 5.
Introduction: Why Flask and SQLite for Your Baking Contest App?
In today's world of AI and rapid app development, knowing how to build a web application that interacts with a database is a crucial skill. Whether you're tracking baking contest entries or building the next viral app, Flask with SQLite offers a lightweight yet powerful combination. This tutorial will guide you through creating a basic Flask website for a baking contest, covering user registration, validation, and result display. By the end, you'll have a solid foundation for the COP4521 assignment 5.
Setting Up Your Flask Project
First, ensure you have Flask and SQLite3 installed. Create a new directory for your project and set up a virtual environment:
mkdir baking_contest_app
cd baking_contest_app
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install flaskCreate the main file app.py and a folder templates for HTML files. Your database contest.db will be created automatically.
Database Schema: Baking Contest Tables
We need two tables: baking_contest_people for users and baking_contest_entry for contest results. Use SQLite3 to create them:
import sqlite3
conn = sqlite3.connect('contest.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS baking_contest_people (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER NOT NULL,
phone_number TEXT NOT NULL,
security_level INTEGER NOT NULL,
login_password TEXT NOT NULL
)''')
c.execute('''CREATE TABLE IF NOT EXISTS baking_contest_entry (
entry_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
name_of_baking_item TEXT,
num_excellent_votes INTEGER,
num_ok_votes INTEGER,
num_bad_votes INTEGER,
FOREIGN KEY (user_id) REFERENCES baking_contest_people(id)
)''')
conn.commit()
conn.close()This schema matches the assignment requirements. Remember to run this script once to initialize your database.
Building the Flask App: Routes and Templates
Your Flask app will have several routes: home, add user, list users, list results, and results page. Let's start with the basic structure:
from flask import Flask, render_template, request, redirect, url_for
import sqlite3
app = Flask(__name__)
# Helper function to get database connection
def get_db():
conn = sqlite3.connect('contest.db')
conn.row_factory = sqlite3.Row
return connHome Page
The home page should have three links as per the assignment. Create templates/home.html:
<h2>Baking Contest Home</h2>
<ul>
<li><a href="/add_user">Add a New Baking Contest User</a></li>
<li><a href="/list_users">List Baking Contest Users</a></li>
<li><a href="/list_results">Baking Contest Results</a></li>
</ul>Add the route in app.py:
@app.route('/')
def home():
return render_template('home.html')Add a New Baking Contest User
This page contains a form with fields: Name, Age, Phone Number, Security Level, Login Password. Create templates/add_user.html:
<h2>Add a New Baking Contest User</h2>
<form method="POST" action="/add_user">
<label for="name">Name:</label>
<input type="text" id="name" name="name"><br>
<label for="age">Age:</label>
<input type="number" id="age" name="age"><br>
<label for="phone">Phone Number:</label>
<input type="text" id="phone" name="phone"><br>
<label for="security">Security Level (1-3):</label>
<input type="number" id="security" name="security"><br>
<label for="password">Login Password:</label>
<input type="password" id="password" name="password"><br>
<button type="submit">Submit</button>
</form>Now implement the POST route with validation:
@app.route('/add_user', methods=['GET', 'POST'])
def add_user():
if request.method == 'POST':
name = request.form['name'].strip()
age = request.form['age']
phone = request.form['phone'].strip()
security = request.form['security']
password = request.form['password'].strip()
errors = []
# Validation rules
if not name:
errors.append('Name cannot be empty.')
try:
age_int = int(age)
if age_int <= 0 or age_int >= 121:
errors.append('Age must be between 1 and 120.')
except ValueError:
errors.append('Age must be a whole number.')
if not phone:
errors.append('Phone number cannot be empty.')
try:
security_int = int(security)
if security_int < 1 or security_int > 3:
errors.append('Security level must be 1, 2, or 3.')
except ValueError:
errors.append('Security level must be a number.')
if not password:
errors.append('Password cannot be empty.')
if errors:
msg = '; '.join(errors)
return render_template('results.html', msg=msg)
else:
conn = get_db()
conn.execute('INSERT INTO baking_contest_people (name, age, phone_number, security_level, login_password) VALUES (?, ?, ?, ?, ?)',
(name, age_int, phone, security_int, password))
conn.commit()
conn.close()
msg = 'Record added successfully!'
return render_template('results.html', msg=msg)
return render_template('add_user.html')List Baking Contest Users
Create templates/list_users.html to display all users in a table:
<h2>Baking Contest Users</h2>
<table border="1">
<tr>
<th>Name</th>
<th>Age</th>
<th>Phone Number</th>
<th>Security Level</th>
<th>Login Password</th>
</tr>
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
<td>{{ user.phone_number }}</td>
<td>{{ user.security_level }}</td>
<td>{{ user.login_password }}</td>
</tr>
{% endfor %}
</table>
<a href="/">Go back to home page</a>Add the route:
@app.route('/list_users')
def list_users():
conn = get_db()
users = conn.execute('SELECT * FROM baking_contest_people').fetchall()
conn.close()
return render_template('list_users.html', users=users)List Contest Results
Create templates/list_results.html to display entries:
<h2>Baking Contest Results</h2>
<table border="1">
<tr>
<th>Entry ID</th>
<th>User ID</th>
<th>Name of Baking Item</th>
<th>Excellent Votes</th>
<th>OK Votes</th>
<th>Bad Votes</th>
</tr>
{% for entry in entries %}
<tr>
<td>{{ entry.entry_id }}</td>
<td>{{ entry.user_id }}</td>
<td>{{ entry.name_of_baking_item }}</td>
<td>{{ entry.num_excellent_votes }}</td>
<td>{{ entry.num_ok_votes }}</td>
<td>{{ entry.num_bad_votes }}</td>
</tr>
{% endfor %}
</table>
<a href="/">Go back to home page</a>Route:
@app.route('/list_results')
def list_results():
conn = get_db()
entries = conn.execute('SELECT * FROM baking_contest_entry').fetchall()
conn.close()
return render_template('list_results.html', entries=entries)Results Page
Create templates/results.html to display the message:
<h2>Result</h2>
<p>{{ msg }}</p>
<a href="/">Go back to home page</a>This page is used for both success and error messages from the add user form.
Testing and Running Your App
Run the app with python app.py and navigate to http://127.0.0.1:5000. Test adding users with valid and invalid data to ensure validation works. For example, an age of 150 should produce an error. Also, test the list pages to confirm data appears correctly.
Trend Connection: Baking Contest App in the Age of AI
Just as AI tools like ChatGPT help generate ideas, your Flask app organizes contest data efficiently. Think of this as a mini-database for a viral baking competition on social media. With the rise of food blogging and online contests, such an app could be the backend for a popular platform.
Common Pitfalls and Tips
- Database not updating: Ensure you commit after inserts.
- Validation errors not showing: Double-check that you pass the
msgvariable to the results template. - Template not found: Make sure all HTML files are in the
templatesfolder. - Foreign key constraint: When inserting entries, ensure the user_id exists in the people table.
Conclusion
You've built a functional Flask website with SQLite for a baking contest, covering user management and result display. This tutorial aligns with COP4521 assignment 5 and provides a foundation for more complex projects. Remember to test thoroughly on linprog before submission. Happy coding!