Bài 8: Full Flask App - Website Quản lý học sinh
Bài học này sẽ hướng dẫn học sinh THPT tạo một Website quản lý học sinh hoàn chỉnh sử dụng Flask, SQLite, Bootstrap, Chart.js và Flask-Login. Chúng ta sẽ tích hợp tất cả các bài trước thành một ứng dụng duy nhất.
1. Mục tiêu bài học
- Hiểu cách tích hợp đăng nhập và phân quyền với Flask-Login.
- Thực hiện đầy đủ các thao tác CRUD trên dữ liệu học sinh.
- Upload hình ảnh học sinh và hiển thị trên website.
- Thống kê điểm trung bình bằng biểu đồ Chart.js.
- Thiết kế giao diện responsive với Bootstrap.
2. Cấu trúc dự án
Chúng ta sẽ tạo cấu trúc dự án Flask như sau:
FlaskStudentApp/
│-- app.py
│-- students.db
│-- templates/
│ │-- base.html
│ │-- login.html
│ │-- dashboard.html
│ │-- student_list.html
│ │-- student_form.html
│ │-- chart.html
│-- static/
│-- css/
│-- images/
3. Cài đặt Flask và các thư viện cần thiết
pip install Flask Flask-Login Flask-WTF WTForms
4. Mã nguồn chính - app.py
Giải thích: Đây là file Flask chính, quản lý routing, database, và đăng nhập.
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_user, login_required, logout_user, UserMixin, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = 'phanchutrinh'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.db'
app.config['UPLOAD_FOLDER'] = 'static/images'
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# User model
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True)
password = db.Column(db.String(150))
role = db.Column(db.String(50)) # admin or teacher
# Student model
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
age = db.Column(db.Integer)
grade = db.Column(db.Float)
photo = db.Column(db.String(100))
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/login', methods=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password, password):
login_user(user)
return redirect(url_for('dashboard'))
flash('Sai tên đăng nhập hoặc mật khẩu!')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/')
@login_required
def dashboard():
students = Student.query.all()
return render_template('dashboard.html', students=students)
# CRUD student
@app.route('/student/add', methods=['GET','POST'])
@login_required
def add_student():
if request.method == 'POST':
name = request.form['name']
age = request.form['age']
grade = request.form['grade']
photo_file = request.files['photo']
photo_path = None
if photo_file:
photo_path = os.path.join(app.config['UPLOAD_FOLDER'], photo_file.filename)
photo_file.save(photo_path)
student = Student(name=name, age=age, grade=grade, photo=photo_file.filename if photo_file else None)
db.session.add(student)
db.session.commit()
flash('Thêm học sinh thành công!')
return redirect(url_for('dashboard'))
return render_template('student_form.html', action="Add")
@app.route('/student/edit/', methods=['GET','POST'])
@login_required
def edit_student(id):
student = Student.query.get_or_404(id)
if request.method == 'POST':
student.name = request.form['name']
student.age = request.form['age']
student.grade = request.form['grade']
photo_file = request.files['photo']
if photo_file:
student.photo = photo_file.filename
photo_file.save(os.path.join(app.config['UPLOAD_FOLDER'], photo_file.filename))
db.session.commit()
flash('Cập nhật học sinh thành công!')
return redirect(url_for('dashboard'))
return render_template('student_form.html', action="Edit", student=student)
@app.route('/student/delete/')
@login_required
def delete_student(id):
student = Student.query.get_or_404(id)
db.session.delete(student)
db.session.commit()
flash('Xóa học sinh thành công!')
return redirect(url_for('dashboard'))
# Chart route
@app.route('/chart')
@login_required
def chart():
students = Student.query.all()
names = [s.name for s in students]
grades = [s.grade for s in students]
return render_template('chart.html', names=names, grades=grades)
if __name__ == '__main__':
db.create_all()
# Tạo user mặc định admin nếu chưa có
if not User.query.filter_by(username='admin').first():
admin = User(username='admin', password=generate_password_hash('123456', method='sha256'), role='admin')
db.session.add(admin)
db.session.commit()
app.run(debug=True)
5. Templates chính
Ví dụ: login.html
Login
Đăng nhập
Tương tự, bạn có thể tạo dashboard.html, student_form.html, chart.html tích hợp Bootstrap & Chart.js để hiển thị dữ liệu và thống kê điểm.
6. Hướng dẫn chạy dự án
- Tạo thư mục dự án và các subfolder
templates,static/images. - Lưu file
app.pyvà các template vào đúng thư mục. - Chạy lệnh
python app.pyvà mở trình duyệthttp://127.0.0.1:5000/. - Đăng nhập với username admin và password 123456.
7. Kết luận
Qua bài học này, học sinh THPT sẽ hiểu cách tạo một **ứng dụng web quản lý học sinh hoàn chỉnh** với Flask, học cách tích hợp **CRUD, đăng nhập, upload hình ảnh, thống kê**, và thiết kế giao diện responsive bằng Bootstrap. Đây là nền tảng để tham gia **hội giảng chuyên đề STEM hoặc các cuộc thi Tin học ứng dụng**.
📌 Danh sách bình luận