🖼️ BÀI 7: UPLOAD ẢNH HỌC SINH + THỐNG KÊ NÂNG CAO
Thực hành Flask – Lưu hình ảnh và hiển thị thống kê nâng cao
🎯 Mục tiêu
- Biết cách upload file ảnh trong Flask.
- Lưu đường dẫn ảnh vào cơ sở dữ liệu.
- Hiển thị hình ảnh học sinh và điểm số trên trang thống kê.
⚙️ 1. Cấu trúc dự án
flask_upload/
├─ app.py
├─ static/uploads/
├─ students.db
└─ templates/
├─ upload.html
├─ gallery.html
💻 2. File app.py
from flask import Flask, render_template, request, redirect, url_for
import sqlite3, os
from werkzeug.utils import secure_filename
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.secret_key = 'uploadkey'
# Tạo bảng
def init_db():
conn = sqlite3.connect('students.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
hoten TEXT,
diem REAL,
image TEXT
)''')
conn.commit()
conn.close()
@app.route('/')
def upload_form():
return render_template('upload.html')
@app.route('/upload', methods=['POST'])
def upload_file():
hoten = request.form['hoten']
diem = request.form['diem']
file = request.files['image']
if file:
filename = secure_filename(file.filename)
path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(path)
conn = sqlite3.connect('students.db')
c = conn.cursor()
c.execute("INSERT INTO students (hoten, diem, image) VALUES (?, ?, ?)", (hoten, diem, filename))
conn.commit()
conn.close()
return redirect('/gallery')
@app.route('/gallery')
def gallery():
conn = sqlite3.connect('students.db')
c = conn.cursor()
c.execute("SELECT hoten, diem, image FROM students")
data = c.fetchall()
conn.close()
return render_template('gallery.html', students=data)
if __name__ == '__main__':
os.makedirs('static/uploads', exist_ok=True)
init_db()
app.run(debug=True)
📋 3. File templates/upload.html
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title>Upload ảnh học sinh</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light d-flex justify-content-center align-items-center vh-100">
<form action="/upload" method="POST" enctype="multipart/form-data" class="p-4 bg-white shadow rounded" style="width:350px;">
<h3 class="text-primary text-center mb-3">🖼️ Upload ảnh học sinh</h3>
<input class="form-control mb-2" type="text" name="hoten" placeholder="Họ và tên" required>
<input class="form-control mb-2" type="number" step="0.1" name="diem" placeholder="Điểm TB" required>
<input class="form-control mb-3" type="file" name="image" accept="image/*" required>
<button class="btn btn-success w-100">Tải lên</button>
<a href="/gallery" class="d-block text-center mt-2">📸 Xem thư viện</a>
</form>
</body>
</html>
📷 4. File templates/gallery.html
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title>Thư viện học sinh</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<h2 class="text-primary text-center mb-4">📸 Thư viện học sinh</h2>
<div class="row">
{% for hs in students %}
<div class="col-md-3 mb-4">
<div class="card shadow">
<img src="{{ url_for('static', filename='uploads/' + hs[2]) }}" class="card-img-top" alt="{{ hs[0] }}">
<div class="card-body text-center">
<h5>{{ hs[0] }}</h5>
<p>Điểm: {{ hs[1] }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</body>
</html>
📈 5. Mở rộng nâng cao
- Tính điểm TB toàn trường, hiển thị biểu đồ (Chart.js).
- Tô màu khác nhau cho học sinh Giỏi / Khá / TB.
- Cho phép upload nhiều ảnh cùng lúc.
© 2025 Trường THPT Phan Chu Trinh – Bài 7: Flask Upload + Thống kê nâng cao
📌 Danh sách bình luận