Creating a virtual classroom platform is a complex project that involves multiple components such as user authentication, course management, live classes, assignments, quizzes, and more. Below, I'll provide an advanced database structure and Flask code for the project. The front-end will use Bootstrap 5 for styling.
Project Structure
virtual_classroom/
│
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ ├── forms.py
│ ├── templates/
│ │ ├── base.html
│ │ ├── login.html
│ │ ├── register.html
│ │ ├── dashboard.html
│ │ ├── course.html
│ │ ├── class.html
│ │ ├── assignment.html
│ │ └── quiz.html
│ └── static/
│ ├── css/
│ │ └── styles.css
│ └── js/
│ └── scripts.js
│
├── config.py
├── run.py
├── requirements.txt
├── venv/ # Virtual environment
├── .gitignore
└── README.md
Database Structure (SQLAlchemy Models)
The database will have the following tables:
- Users: Stores user information (students, teachers, admins).
- Courses: Stores course details.
- Enrollments: Tracks which users are enrolled in which courses.
- Classes: Stores live class schedules.
- Assignments: Stores assignments for courses.
- Submissions: Tracks assignment submissions by students.
- Quizzes: Stores quizzes for courses.
- QuizResults: Tracks quiz results for students.
Flask Application Structure
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
role = db.Column(db.String(20), nullable=False) # student, teacher, admin
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# Relationships
enrollments = db.relationship('Enrollment', backref='user', lazy=True)
submissions = db.relationship('Submission', backref='user', lazy=True)
quiz_results = db.relationship('QuizResult', backref='user', lazy=True)
class Course(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
teacher_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# Relationships
enrollments = db.relationship('Enrollment', backref='course', lazy=True)
classes = db.relationship('Class', backref='course', lazy=True)
assignments = db.relationship('Assignment', backref='course', lazy=True)
quizzes = db.relationship('Quiz', backref='course', lazy=True)
class Enrollment(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'), nullable=False)
enrolled_at = db.Column(db.DateTime, default=datetime.utcnow)
class Class(db.Model):
id = db.Column(db.Integer, primary_key=True)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
schedule = db.Column(db.DateTime, nullable=False)
meeting_link = db.Column(db.String(500), nullable=False)
class Assignment(db.Model):
id = db.Column(db.Integer, primary_key=True)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
deadline = db.Column(db.DateTime, nullable=False)
# Relationships
submissions = db.relationship('Submission', backref='assignment', lazy=True)
class Submission(db.Model):
id = db.Column(db.Integer, primary_key=True)
assignment_id = db.Column(db.Integer, db.ForeignKey('assignment.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
file_path = db.Column(db.String(500), nullable=False)
submitted_at = db.Column(db.DateTime, default=datetime.utcnow)
class Quiz(db.Model):
id = db.Column(db.Integer, primary_key=True)
course_id = db.Column(db.Integer, db.ForeignKey('course.id'), nullable=False)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
questions = db.Column(db.JSON, nullable=False) # Store questions as JSON
created_at = db.Column(db.DateTime, default=datetime.utcnow)
# Relationships
quiz_results = db.relationship('QuizResult', backref='quiz', lazy=True)
class QuizResult(db.Model):
id = db.Column(db.Integer, primary_key=True)
quiz_id = db.Column(db.Integer, db.ForeignKey('quiz.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
score = db.Column(db.Float, nullable=False)
submitted_at = db.Column(db.DateTime, default=datetime.utcnow)
Configuration
import os
class Config:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///site.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = os.environ.get('SECRET_KEY') or 'your_secret_key'
Routes
from flask import render_template, redirect, url_for, flash, request
from . import db
from .models import User, Course, Enrollment, Class, Assignment, Submission, Quiz, QuizResult
from .forms import LoginForm, RegistrationForm
from flask_login import login_user, logout_user, login_required, current_user
@app.route('/')
def home():
return render_template('base.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and user.password == form.password.data: # Use hashed passwords in production
login_user(user)
return redirect(url_for('dashboard'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return render_template('login.html', form=form)
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data, password=form.password.data, role='student')
db.session.add(user)
db.session.commit()
flash('Your account has been created! You can now log in', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
@app.route('/dashboard')
@login_required
def dashboard():
courses = Course.query.all()
return render_template('dashboard.html', courses=courses)
@app.route('/course/<int:course_id>')
@login_required
def course(course_id):
course = Course.query.get_or_404(course_id)
return render_template('course.html', course=course)
@app.route('/class/<int:class_id>')
@login_required
def class_view(class_id):
class_info = Class.query.get_or_404(class_id)
return render_template('class.html', class_info=class_info)
@app.route('/assignment/<int:assignment_id>', methods=['GET', 'POST'])
@login_required
def assignment(assignment_id):
assignment = Assignment.query.get_or_404(assignment_id)
if request.method == 'POST':
# Handle file upload and submission logic here
pass
return render_template('assignment.html', assignment=assignment)
@app.route('/quiz/<int:quiz_id>', methods=['GET', 'POST'])
@login_required
def quiz(quiz_id):
quiz = Quiz.query.get_or_404(quiz_id)
if request.method == 'POST':
# Handle quiz submission logic here
pass
return render_template('quiz.html', quiz=quiz)
Forms
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField, DateTimeField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
class AssignmentForm(FlaskForm):
title = StringField('Title', validators=[DataRequired()])
description = TextAreaField('Description', validators=[DataRequired()])
deadline = DateTimeField('Deadline', format='%Y-%m-%d %H:%M:%S', validators=[DataRequired()])
submit = SubmitField('Create Assignment')
class QuizForm(FlaskForm):
title = StringField('Title', validators=[DataRequired()])
description = TextAreaField('Description', validators=[DataRequired()])
questions = TextAreaField('Questions (JSON format)', validators=[DataRequired()])
submit = SubmitField('Create Quiz')
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">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<title>Virtual Classroom</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('home') }}">Virtual Classroom</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('dashboard') }}">Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register') }}">Register</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-warning" role="alert">
{% for message in messages %}
{{ message }}<br>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
login.html
{% extends "base.html" %}
{% block content %}
<h2>Login</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.email.label(class="form-label") }}
{{ form.email(class="form-control") }}
</div>
<div class="mb-3">
{{ form.password.label(class="form-label") }}
{{ form.password(class="form-control") }}
</div>
<div class="mb-3">
{{ form.submit(class="btn btn-primary") }}
</div>
</form>
{% endblock %}
register.html
{% extends "base.html" %}
{% block content %}
<h2>Register</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.username.label(class="form-label") }}
{{ form.username(class="form-control") }}
</div>
<div class="mb-3">
{{ form.email.label(class="form-label") }}
{{ form.email(class="form-control") }}
</div>
<div class="mb-3">
{{ form.password.label(class="form-label") }}
{{ form.password(class="form-control") }}
</div>
<div class="mb-3">
{{ form.confirm_password.label(class="form-label") }}
{{ form.confirm_password(class="form-control") }}
</div>
<div class="mb-3">
{{ form.submit(class="btn btn-primary") }}
</div>
</form>
{% endblock %}
dashboard.html
{% extends "base.html" %}
{% block content %}
<h2>Dashboard</h2>
<div class="list-group">
{% for course in courses %}
<a href="{{ url_for('course', course_id=course.id) }}" class="list-group-item list-group-item-action">
{{ course.title }}
</a>
{% endfor %}
</div>
{% endblock %}
course.html
{% extends "base.html" %}
{% block content %}
<h2>{{ course.title }}</h2>
<p>{{ course.description }}</p>
<h3>Classes</h3>
<ul>
{% for class_info in course.classes %}
<li><a href="{{ url_for('class_view', class_id=class_info.id) }}">{{ class_info.title }}</a></li>
{% endfor %}
</ul>
<h3>Assignments</h3>
<ul>
{% for assignment in course.assignments %}
<li><a href="{{ url_for('assignment', assignment_id=assignment.id) }}">{{ assignment.title }}</a></li>
{% endfor %}
</ul>
<h3>Quizzes</h3>
<ul>
{% for quiz in course.quizzes %}
<li><a href="{{ url_for('quiz', quiz_id=quiz.id) }}">{{ quiz.title }}</a></li>
{% endfor %}
</ul>
{% endblock %}
class.html
{% extends "base.html" %}
{% block content %}
<h2>{{ class_info.title }}</h2>
<p>{{ class_info.description }}</p>
<p>Scheduled for: {{ class_info.schedule }}</p>
<p><a href="{{ class_info.meeting_link }}" class="btn btn-primary">Join Class</a></p>
{% endblock %}
assignment.html
{% extends "base.html" %}
{% block content %}
<h2>{{ assignment.title }}</h2>
<p>{{ assignment.description }}</p>
<p>Deadline: {{ assignment.deadline }}</p>
<form method="POST" enctype="multipart/form-data">
<div class="mb-3">
<input type="file" name="file" class="form-control" required>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Submit Assignment</button>
</div>
</form>
{% endblock %}
quiz.html
{% extends "base.html" %}
{% block content %}
<h2>{{ quiz.title }}</h2>
<p>{{ quiz.description }}</p>
<form method="POST">
{% for question in quiz.questions %}
<div class="mb-3">
<label>{{ question['question'] }}</label>
<input type="text" name="answers[{{ loop.index }}]" class="form-control" required>
</div>
{% endfor %}
<div class="mb-3">
<button type="submit" class="btn btn-primary">Submit Quiz</button>
</div>
</form>
{% endblock %}
Styles
body {
background-color: #f8f9fa;
}
.navbar {
margin-bottom: 20px;
}
Scripts
// Custom JavaScript can be added here
Running the Application
To run the application, ensure you have Flask and Flask-SQLAlchemy installed. You can set up a virtual environment and install the required packages using:
pip install Flask Flask-SQLAlchemy Flask-WTF Flask-Login
Then, run the application with:
flask run