Creating an advanced-level Event Management System using Flask and Bootstrap 5 involves designing a robust database structure, implementing Flask routes, and creating dynamic web pages. Below is a detailed implementation:
1. Database Structure
The database will include tables for users, events, attendees, event categories, and event organizers. We'll use SQLAlchemy for ORM.
Database Models
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(100), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(200), nullable=False)
role = db.Column(db.String(50), nullable=False) # Admin, Organizer, Attendee
events_organized = db.relationship('Event', backref='organizer', lazy=True)
attendances = db.relationship('Attendance', backref='attendee', lazy=True)
class EventCategory(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
events = db.relationship('Event', backref='category', lazy=True)
class Event(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=False)
date = db.Column(db.DateTime, nullable=False)
location = db.Column(db.String(200), nullable=False)
capacity = db.Column(db.Integer, nullable=False)
organizer_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('event_category.id'), nullable=False)
attendees = db.relationship('Attendance', backref='event', lazy=True)
class Attendance(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
registration_date = db.Column(db.DateTime, default=datetime.utcnow)
Flask Application Structure
Here’s the directory structure for the project:
advanced_event_management/
│
├── app/
│ ├── __init__.py # Initialize the Flask app and database
│ ├── models.py # Database models (User , Event, Attendance, EventCategory)
│ ├── routes.py # Application routes and views
│ ├── forms.py # Forms for user registration, login, event posting, and applications
│ ├── static/ # Static files (CSS, JS, images)
│ │ ├── css/
│ │ │ └── styles.css # Custom CSS styles
│ │ └── js/
│ │ └── scripts.js # Custom JavaScript files
│ └── templates/ # HTML templates
│ ├── base.html # Base layout for templates
│ ├── index.html # Home page
│ ├── login.html # Login page
│ ├── register.html # Registration page
│ ├── dashboard.html # User dashboard
│ ├── post_event.html # Event posting page
│ ├── event_detail.html # Event details page
│ └── my_events.html # User's events page
│
├── migrations/ # Database migration files (if using Flask-Migrate)
│
├── config.py # Configuration settings for the app
│
├── requirements.txt # Python package dependencies
│
└── run.py # Entry point to run the application
2. Flask Application Setup
Install required packages:
pip install flask flask-sqlalchemy flask-wtf flask-login flask-bootstrap5
Create the Flask app:
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap5 import Bootstrap
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.config['SECRET_KEY'] = 'supersecretkey'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///event_management.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
Bootstrap(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Create database tables
with app.app_context():
db.create_all()
3. Flask Routes and Views
Implement routes for authentication, event management, and attendee registration.
@app.route('/')
def index():
events = Event.query.all()
return render_template('index.html', events=events)
@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_hash, password):
login_user(user)
return redirect(url_for('index'))
flash('Invalid username or password')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
email = request.form['email']
password = request.form['password']
role = request.form['role']
hashed_password = generate_password_hash(password)
new_user = User(username=username, email=email, password_hash=hashed_password, role=role)
db.session.add(new_user)
db.session.commit()
flash('Registration successful! You can now log in.')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/events')
def events():
events = Event.query.all()
return render_template('events.html', events=events)
@app.route('/event/<int:id>', methods=['GET', 'POST'])
def event_detail(id):
event = Event.query.get_or_404(id)
if request.method == 'POST':
if current_user.is_authenticated:
if len(event.attendees) < event.capacity:
new_attendance = Attendance(user_id=current_user.id, event_id=event.id)
db.session.add(new_attendance)
db.session.commit()
flash('You have successfully registered for the event!')
else:
flash('Event is fully booked.')
return redirect(url_for('event_detail', id=event.id))
else:
flash('You need to log in to register for events.')
return redirect(url_for('login'))
return render_template('event_detail.html', event=event)
@app.route('/organizer/events')
@login_required
def organizer_events():
if current_user.role != 'Organizer':
flash('Access denied.')
return redirect(url_for('index'))
events = Event.query.filter_by(organizer_id=current_user.id).all()
return render_template('organizer_events.html', events=events)
@app.route('/organizer/event/new', methods=['GET', 'POST'])
@login_required
def new_event():
if current_user.role != 'Organizer':
flash('Access denied.')
return redirect(url_for('index'))
if request.method == 'POST':
name = request.form['name']
description = request.form['description']
date = request.form['date']
location = request.form['location']
capacity = request.form['capacity']
category_id = request.form['category']
new_event = Event(name=name, description=description, date=date, location=location, capacity=capacity, organizer_id=current_user.id, category_id=category_id)
db.session.add(new_event)
db.session.commit()
flash('Event created successfully!')
return redirect(url_for('organizer_events'))
categories = EventCategory.query.all()
return render_template('new_event.html', categories=categories)
if __name__ == '__main__':
app.run(debug=True)
5. HTML Templates
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 rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
<title>{% block title %}Event Management System{% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index') }}">Event Management</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('events') }}">Events</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>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('organizer_events') }}">My Events</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-info">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
</body>
</html>
templates/index.html
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<h1>Welcome to the Event Management System</h1>
<p>Discover and register for exciting events!</p>
<a href="{{ url_for('events') }}" class="btn btn-primary">View Events</a>
{% endblock %}
templates/login.html
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h1>Login</h1>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
{% endblock %}
templates/register.html
{% extends 'base.html' %}
{% block title %}Register{% endblock %}
{% block content %}
<h1>Register</h1>
<form method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
{% endblock %}
templates/dashboard.html
{% extends 'base.html' %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h2>Dashboard</h2>
<p>Welcome, {{ current_user.username }}!</p>
{% endblock %}
templates/add_expense.html
{% extends 'base.html' %}
{% block title %}Add Expense{% endblock %}
{% block content %}
<h2>Add Expense</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.amount.label(class="form-label") }}
{{ form.amount(class="form-control") }}
</div>
<div class="mb-3">
{{ form.description.label(class="form-label") }}
{{ form.description(class="form-control") }}
</div>
<div class="mb-3">
{{ form.category.label(class="form-label") }}
{{ form.category(class="form-control") }}
</div>
<button type="submit" class="btn btn-primary">Add Expense</button>
</form>
{% endblock %}
templates/view_expenses.html
{% extends 'base.html' %}
{% block title %}View Expenses{% endblock %}
{% block content %}
<h2>Your Expenses</h2>
<table class="table">
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col">Description</th>
<th scope="col">Amount</th>
<th scope="col">Category</th>
</tr>
</thead>
<tbody>
{% for expense in expenses %}
<tr>
<td>{{ expense.date.strftime('%Y-%m-%d') }}</td>
<td>{{ expense.description }}</td>
<td>${{ expense.amount }}</td>
<td>{{ expense.category.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
templates/add_category.html
{% extends 'base.html' %}
{% block title %}Add Category{% endblock %}
{% block content %}
<h2>Add Category</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.name.label(class="form-label") }}
{{ form.name(class="form-control") }}
</div>
<button type="submit" class="btn btn-primary">Add Category</button>
</form>
{% endblock %}
6. Forms for Flask-WTF
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, FloatField, TextAreaField, SelectField, SubmitField
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=50)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
class ExpenseForm(FlaskForm):
amount = FloatField('Amount', validators=[DataRequired()])
description = TextAreaField('Description', validators=[DataRequired()])
category = SelectField('Category', coerce=int)
submit = SubmitField('Add Expense')
class CategoryForm(FlaskForm):
name = StringField('Category Name', validators=[DataRequired()])
submit = SubmitField('Add Category')
7. Static Files
static/css/styles.css
body {
background-color: #f8f9fa;
}
.navbar {
margin-bottom: 20px;
}
.table {
margin-top: 20px;
}
8. JavaScript (if needed)
static/js/scripts.js
// Custom JavaScript can be added here
9. Running the Application
To run the application, ensure you have the required packages installed as specified in requirements.txt, then execute:
python run.py
This structure and code provide a comprehensive foundation for an advanced Expense Tracker App using Flask and Bootstrap 5, allowing for user authentication, expense management, and category organization.