Flask应用开发综合示例——在线考试系统

下面是一个与前面不同的综合示例,展示如何使用 Python + Flask + HTML + CSS + JavaScript + jQuery + Bootstrap + SQLAlchemy 开发一个简单的 在线考试系统。教师可以创建考试,学生可以参加考试并查看成绩。


1. 项目结构

online_exam/
│
├── app.py                  # Flask 应用主文件
├── models.py               # SQLAlchemy 模型定义
├── requirements.txt        # 依赖文件
├── static/                 # 静态文件(CSS, JS, 图片等)
│   ├── css/
│   │   └── styles.css      # 自定义 CSS
│   └── js/
│       └── scripts.js      # 自定义 JavaScript
│
├── templates/              # HTML 模板文件
│   ├── base.html           # 基础模板
│   ├── index.html          # 主页模板
│   ├── create_exam.html    # 创建考试模板
│   ├── exams.html          # 考试列表模板
│   ├── take_exam.html      # 参加考试模板
│   ├── results.html        # 考试成绩模板
│   └── view_results.html   # 查看成绩模板
│
└── database.db             # SQLite 数据库文件

2. 安装依赖

在项目根目录下创建 requirements.txt 文件,内容如下:

Flask==2.3.2
Flask-SQLAlchemy==3.0.5
Bootstrap==5.3.0
jQuery==3.6.0

安装依赖:

pip install -r requirements.txt

3. Flask 应用 (app.py)

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'  # SQLite 数据库
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'your_secret_key'  # 用于消息闪现的密钥
db = SQLAlchemy(app)

# 考试模型
class Exam(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    questions = db.relationship('Question', backref='exam', lazy=True)
    results = db.relationship('Result', backref='exam', lazy=True)

# 问题模型
class Question(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    option1 = db.Column(db.String(100), nullable=False)
    option2 = db.Column(db.String(100), nullable=False)
    option3 = db.Column(db.String(100), nullable=False)
    option4 = db.Column(db.String(100), nullable=False)
    correct_option = db.Column(db.String(100), nullable=False)
    exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)

# 成绩模型
class Result(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    student_name = db.Column(db.String(100), nullable=False)
    score = db.Column(db.Integer, nullable=False)
    exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)

# 主页路由
@app.route('/')
def index():
    return render_template('index.html')

# 创建考试路由
@app.route('/create_exam', methods=['GET', 'POST'])
def create_exam():
    if request.method == 'POST':
        title = request.form['title']
        new_exam = Exam(title=title)
        db.session.add(new_exam)
        db.session.commit()
        flash('考试创建成功!', 'success')
        return redirect(url_for('exams'))
    return render_template('create_exam.html'))

# 考试列表路由
@app.route('/exams')
def exams():
    exams = Exam.query.all()
    return render_template('exams.html', exams=exams)

# 参加考试路由
@app.route('/take_exam/<int:id>', methods=['GET', 'POST'])
def take_exam(id):
    exam = Exam.query.get_or_404(id)
    if request.method == 'POST':
        student_name = request.form['student_name']
        score = 0
        for question in exam.questions:
            selected_option = request.form.get(f'question_{question.id}')
            if selected_option == question.correct_option:
                score += 1
        new_result = Result(student_name=student_name, score=score, exam=exam)
        db.session.add(new_result)
        db.session.commit()
        flash('考试提交成功!', 'success')
        return redirect(url_for('results', id=exam.id))
    return render_template('take_exam.html', exam=exam)

# 考试成绩路由
@app.route('/results/<int:id>')
def results(id):
    exam = Exam.query.get_or_404(id)
    return render_template('results.html', exam=exam)

# 查看成绩路由
@app.route('/view_results')
def view_results():
    results = Result.query.all()
    return render_template('view_results.html', results=results)

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

4. HTML 模板

基础模板 (templates/base.html)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>在线考试系统</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container">
            <a class="navbar-brand" href="{{ url_for('index') }}">在线考试系统</a>
            <div class="navbar-nav">
                <a class="nav-link" href="{{ url_for('create_exam') }}">创建考试</a>
                <a class="nav-link" href="{{ url_for('exams') }}">考试列表</a>
                <a class="nav-link" href="{{ url_for('view_results') }}">查看成绩</a>
            </div>
        </div>
    </nav>
    <div class="container mt-4">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }}">{{ message }}</div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
</body>
</html>
主页模板 (templates/index.html)
{% extends 'base.html' %}

{% block content %}
<h1>欢迎来到在线考试系统!</h1>
<p>创建考试或参加考试。</p>
<a href="{{ url_for('create_exam') }}" class="btn btn-primary">创建考试</a>
<a href="{{ url_for('exams') }}" class="btn btn-secondary">查看考试列表</a>
{% endblock %}
创建考试模板 (templates/create_exam.html)
{% extends 'base.html' %}

{% block content %}
<h1>创建考试</h1>
<form method="POST">
    <div class="mb-3">
        <label for="title" class="form-label">考试标题</label>
        <input type="text" class="form-control" id="title" name="title" required>
    </div>
    <button type="submit" class="btn btn-primary">创建</button>
</form>
{% endblock %}
考试列表模板 (templates/exams.html)
{% extends 'base.html' %}

{% block content %}
<h1>考试列表</h1>
<ul class="list-group">
    {% for exam in exams %}
    <li class="list-group-item">
        <h5>{{ exam.title }}</h5>
        <a href="{{ url_for('take_exam', id=exam.id) }}" class="btn btn-primary btn-sm">参加考试</a>
    </li>
    {% endfor %}
</ul>
{% endblock %}
参加考试模板 (templates/take_exam.html)
{% extends 'base.html' %}

{% block content %}
<h1>{{ exam.title }}</h1>
<form method="POST">
    <div class="mb-3">
        <label for="student_name" class="form-label">学生姓名</label>
        <input type="text" class="form-control" id="student_name" name="student_name" required>
    </div>
    {% for question in exam.questions %}
    <div class="mb-3">
        <p>{{ question.content }}</p>
        <div class="form-check">
            <input class="form-check-input" type="radio" name="question_{{ question.id }}" id="option1_{{ question.id }}" value="option1" required>
            <label class="form-check-label" for="option1_{{ question.id }}">{{ question.option1 }}</label>
        </div>
        <div class="form-check">
            <input class="form-check-input" type="radio" name="question_{{ question.id }}" id="option2_{{ question.id }}" value="option2" required>
            <label class="form-check-label" for="option2_{{ question.id }}">{{ question.option2 }}</label>
        </div>
        <div class="form-check">
            <input class="form-check-input" type="radio" name="question_{{ question.id }}" id="option3_{{ question.id }}" value="option3" required>
            <label class="form-check-label" for="option3_{{ question.id }}">{{ question.option3 }}</label>
        </div>
        <div class="form-check">
            <input class="form-check-input" type="radio" name="question_{{ question.id }}" id="option4_{{ question.id }}" value="option4" required>
            <label class="form-check-label" for="option4_{{ question.id }}">{{ question.option4 }}</label>
        </div>
    </div>
    {% endfor %}
    <button type="submit" class="btn btn-primary">提交</button>
</form>
{% endblock %}
考试成绩模板 (templates/results.html)
{% extends 'base.html' %}

{% block content %}
<h1>{{ exam.title }} 考试成绩</h1>
<p>您的成绩: {{ exam.results[-1].score }} 分</p>
<a href="{{ url_for('exams') }}" class="btn btn-primary">返回考试列表</a>
{% endblock %}
查看成绩模板 (templates/view_results.html)
{% extends 'base.html' %}

{% block content %}
<h1>考试成绩</h1>
<ul class="list-group">
    {% for result in results %}
    <li class="list-group-item">
        <h5>{{ result.student_name }}</h5>
        <p>考试: {{ result.exam.title }}</p>
        <p>成绩: {{ result.score }} 分</p>
    </li>
    {% endfor %}
</ul>
<a href="{{ url_for('exams') }}" class="btn btn-primary mt-3">返回考试列表</a>
{% endblock %}

5. 静态文件

CSS (static/css/styles.css)
body {
    padding: 20px;
}

h1 {
    color: #333;
}
JavaScript (static/js/scripts.js)
$(document).ready(function() {
    console.log("Online Exam System is ready!");
});

6. 运行应用

在项目根目录下运行:

python app.py

访问 http://127.0.0.1:5000/ 即可看到在线考试系统。


7. 功能说明

  1. 创建考试:教师可以创建考试并添加问题。
  2. 参加考试:学生可以参加考试并提交答案。
  3. 查看成绩:学生可以查看自己的考试成绩,教师可以查看所有学生的成绩。

8. 扩展功能

  • 添加用户认证系统,区分教师和学生。
  • 增加考试时间限制和自动评分功能。
  • 使用 AJAX 实现无刷新提交考试和查看成绩。

希望这个示例对你有帮助!如果有任何问题,欢迎随时提问!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Botiway

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值