Student Tracker – Performance Task
Complete Project Report (with Full Source Code)
Student: Deepak Kumar Polai
This document presents the Student Tracker web application built with Flask. It allows adding students, recording
grades, viewing individual student details, and a dashboard/homepage. Below you will find the project overview,
features, how to run, and the complete source code of all files.
Key Features
Feature Description
Add Student Create new student records (name, roll number, etc.).
Add Grade Add subject-wise grades for a student.
Students Page List all students with quick links to view details or delete.
Student Detail See grades table, average, and manage entries.
Styled UI Clean, simple CSS for a professional look.
How to Run (VS Code)
1) Open the project folder in VS Code.
2) Create virtual environment:
- Windows: python -m venv venv
venv\Scripts\activate
- Mac/Linux: python3 -m venv venv
source venv/bin/activate
3) Install dependencies: pip install -r [Link]
4) Run the app: python [Link]
5) Open browser at: [Link]
6) Stop server: CTRL + C
Project Structure
[Link]
[Link]
templates/[Link]
templates/[Link]
templates/[Link]
templates/add_student.html
templates/student_detail.html
templates/add_grade.html
static/[Link]
1. [Link]
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import func
import os
app = Flask(__name__)
[Link]['SECRET_KEY'] = [Link]('SECRET_KEY', 'dev-secret')
[Link]['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///[Link]'
[Link]['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
# Models
class Student([Link]):
id = [Link]([Link], primary_key=True)
roll_number = [Link]([Link](64), unique=True, nullable=False)
name = [Link]([Link](120), nullable=False)
grades = [Link]('Grade', backref='student', cascade='all, delete-orphan', lazy=True)
def average(self):
if not [Link]:
return 0.0
return sum([Link] for g in [Link]) / len([Link])
class Grade([Link]):
id = [Link]([Link], primary_key=True)
subject = [Link]([Link](64), nullable=False)
score = [Link]([Link], nullable=False)
student_id = [Link]([Link], [Link]('[Link]'), nullable=False)
# CLI command to initialize the database
@[Link]('init-db')
def init_db():
db.create_all()
print('Database initialized.')
# Routes
@[Link]('/')
def index():
student_count = [Link]()
grade_count = [Link]()
subject_avgs = [Link]([Link], [Link]([Link])).group_by([Link]).all()
return render_template('[Link]', student_count=student_count, grade_count=grade_count, subject_a
@[Link]('/students')
def students():
q = [Link]('q', '').strip()
if q:
items = [Link](([Link](f'%{q}%')) | (Student.roll_number.ilike(f'%{q}%
else:
items = [Link].order_by(Student.roll_number).all()
return render_template('[Link]', students=items, q=q)
@[Link]('/students/add', methods=['GET', 'POST'])
def add_student():
if [Link] == 'POST':
name = [Link]('name', '').strip()
roll = [Link]('roll_number', '').strip()
if not name or not roll:
flash('Name and Roll Number are required.', 'error')
return redirect(url_for('add_student'))
if [Link].filter_by(roll_number=roll).first():
flash('Roll number already exists.', 'error')
return redirect(url_for('add_student'))
s = Student(name=name, roll_number=roll)
[Link](s)
[Link]()
flash('Student added successfully.', 'success')
return redirect(url_for('students'))
return render_template('add_student.html')
@[Link]('/students/<int:student_id>')
def student_detail(student_id):
s = [Link].get_or_404(student_id)
return render_template('student_detail.html', s=s)
@[Link]('/students/<int:student_id>/grades/add', methods=['GET', 'POST'])
def add_grade(student_id):
s = [Link].get_or_404(student_id)
if [Link] == 'POST':
subject = [Link]('subject', '').strip()
try:
score = float([Link]('score', '').strip())
except ValueError:
flash('Score must be a number.', 'error')
return redirect(url_for('add_grade', student_id=student_id))
if not (0 <= score <= 100):
flash('Score must be between 0 and 100.', 'error')
return redirect(url_for('add_grade', student_id=student_id))
if not subject:
flash('Subject is required.', 'error')
return redirect(url_for('add_grade', student_id=student_id))
g = Grade(subject=subject, score=score, student=s)
[Link](g)
[Link]()
flash('Grade added.', 'success')
return redirect(url_for('student_detail', student_id=student_id))
return render_template('add_grade.html', s=s)
@[Link]('/grades/<int:grade_id>/delete', methods=['POST'])
def delete_grade(grade_id):
g = [Link].get_or_404(grade_id)
sid = g.student_id
[Link](g)
[Link]()
flash('Grade deleted.', 'success')
return redirect(url_for('student_detail', student_id=sid))
@[Link]('/students/<int:student_id>/delete', methods=['POST'])
def delete_student(student_id):
s = [Link].get_or_404(student_id)
[Link](s)
[Link]()
flash('Student deleted.', 'success')
return redirect(url_for('students'))
if __name__ == '__main__':
with app.app_context():
db.create_all()
[Link](debug=True)
2. [Link]
Flask
Flask-SQLAlchemy
SQLAlchemy
3. templates/[Link]
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Student Tracker</title>
<link rel="stylesheet" href="{{ url_for('static', filename='[Link]') }}">
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">Dashboard</a>
<a href="{{ url_for('students') }}">Students</a>
<a href="{{ url_for('add_student') }}">+ Add Student</a>
</nav>
<main>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for category, msg in messages %}
<li class="{{ category }}">{{ msg }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
</body>
</html>
4. templates/[Link]
{% extends '[Link]' %}
{% block content %}
<h1>Dashboard</h1>
<p>Total Students: {{ student_count }}</p>
<p>Total Grades: {{ grade_count }}</p>
<h2>Subject Averages</h2>
<ul>
{% for subject, avg in subject_avgs %}
<li>{{ subject }}: {{ '%.2f'|format(avg) }}</li>
{% else %}
<li>No grades yet.</li>
{% endfor %}
</ul>
{% endblock %}
5. templates/[Link]
{% extends '[Link]' %}
{% block content %}
<h1>Students</h1>
<form method="get">
<input type="text" name="q" value="{{ q }}" placeholder="Search">
<button type="submit">Search</button>
</form>
<ul>
{% for s in students %}
<li>{{ s.roll_number }} - {{ [Link] }} (Avg: {{ '%.2f'|format([Link]()) }})
<a href="{{ url_for('student_detail', student_id=[Link]) }}">View</a>
<form action="{{ url_for('delete_student', student_id=[Link]) }}" method="post" style="display:inline;
<button type="submit">Delete</button>
</form>
</li>
{% else %}
<li>No students found.</li>
{% endfor %}
</ul>
{% endblock %}
6. templates/add_student.html
{% extends '[Link]' %}
{% block content %}
<h1>Add Student</h1>
<form method="post">
<label>Name: <input type="text" name="name" required></label><br>
<label>Roll Number: <input type="text" name="roll_number" required></label><br>
<button type="submit">Add</button>
</form>
{% endblock %}
7. templates/student_detail.html
{% extends '[Link]' %}
{% block content %}
<h1>{{ [Link] }} ({{ s.roll_number }})</h1>
<h2>Grades</h2>
<ul>
{% for g in [Link] %}
<li>{{ [Link] }}: {{ [Link] }}
<form action="{{ url_for('delete_grade', grade_id=[Link]) }}" method="post" style="display:inline;">
<button type="submit">Delete</button>
</form>
</li>
{% else %}
<li>No grades yet.</li>
{% endfor %}
</ul>
<a href="{{ url_for('add_grade', student_id=[Link]) }}">+ Add Grade</a>
<p>Average: {{ '%.2f'|format([Link]()) }}</p>
{% endblock %}
8. templates/add_grade.html
{% extends '[Link]' %}
{% block content %}
<h1>Add Grade for {{ [Link] }}</h1>
<form method="post">
<label>Subject: <input type="text" name="subject" required></label><br>
<label>Score: <input type="number" step="0.01" min="0" max="100" name="score" required></label><br>
<button type="submit">Add Grade</button>
</form>
{% endblock %}
9. static/[Link]
body { font-family: Arial, sans-serif; margin: 20px; } nav a { margin-right: 10px; }