Flask Projects With Source Code

Bus Booking System Project In Flask


Creating an advanced-level Bus Booking System with Flask and Bootstrap 5 involves designing a robust database structure, implementing backend logic, and creating responsive frontend pages. Below is a detailed implementation:

1. Database Structure

The database will be designed using SQLAlchemy (ORM for Flask). Here's the schema:

Tables

  • Users: Stores user information.
  • Buses: Stores bus details.
  • Routes: Stores route information.
  • Bookings: Stores booking details.
  • Payments: Stores payment details.

SQL Schema


CREATE TABLE Users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) `UNIQUE` NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    role ENUM('admin', 'manager', 'sales') NOT NULL
);
CREATE TABLE Brands (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) `UNIQUE` NOT NULL
);
CREATE TABLE Models (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    brand_id INT,
    FOREIGN KEY (brand_id) REFERENCES Brands(id)
);
CREATE TABLE Cars (
    id INT PRIMARY KEY AUTO_INCREMENT,
    model_id INT,
    year `INT` NOT NULL,
    color VARCHAR(50),
    price DECIMAL(10, 2) NOT NULL,
    mileage INT,
    FOREIGN KEY (model_id) REFERENCES Models(id)
);
CREATE TABLE Inventory (
    id INT PRIMARY KEY AUTO_INCREMENT,
    car_id INT UNIQUE,
    quantity INT DEFAULT 0,
    FOREIGN KEY (car_id) REFERENCES Cars(id)
);
CREATE TABLE Customers (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) `UNIQUE` NOT NULL,
    phone VARCHAR(15)
);
CREATE TABLE Sales (
    id INT PRIMARY KEY AUTO_INCREMENT,
    car_id INT,
    customer_id INT,
    sale_date `DATE` NOT NULL,
    sale_price DECIMAL(10, 2) NOT NULL,
    FOREIGN KEY (car_id) REFERENCES Cars(id),
    FOREIGN KEY (customer_id) REFERENCES Customers(id)
);

2. Flask Application Structure

The Flask application will have the following structure:


bus_booking_system/
│
├── app.py
├── models.py
├── forms.py
├── templates/
│   ├── base.html
│   ├── index.html
│   ├── login.html
│   ├── register.html
│   ├── search_buses.html
│   ├── booking.html
│   ├── payment.html
│   ├── dashboard.html
│   └── admin/
│       ├── add_bus.html
│       ├── manage_buses.html
│       └── manage_routes.html
├── static/
│   ├── css/
│   │   └── styles.css
│   ├── js/
│   │   └── scripts.js
│   └── images/
└── requirements.txt

3. Flask Application Code

app.py


from flask import Flask, render_template, request, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from models import db, User, Bus, Route, Booking, Payment
from forms import LoginForm, RegistrationForm, BookingForm, PaymentForm
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///bus_booking.db'
db.init_app(app)
# Routes
@app.route('/')
def index():
    return render_template('index.html')
@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)
        db.session.add(user)
        db.session.commit()
        flash('Registration successful! Please login.', 'success')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)
@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
            session['user_id'] = user.id
            flash('Login successful!', 'success')
            return redirect(url_for('dashboard'))
        flash('Login failed. Check your email and password.', 'danger')
    return render_template('login.html', form=form)
@app.route('/dashboard')
def dashboard():
    if 'user_id' not in session:
        return redirect(url_for('login'))
    user = User.query.get(session['user_id'])
    return render_template('dashboard.html', user=user)
@app.route('/search_buses', methods=['GET', 'POST'])
def search_buses():
    if request.method == 'POST':
        source = request.form['source']
        destination = request.form['destination']
        buses = Bus.query.join(Route).filter(Route.source == source, Route.destination == destination).all()
        return render_template('search_buses.html', buses=buses)
    return render_template('search_buses.html', buses=[])
@app.route('/book/<int:bus_id>', methods=['GET', 'POST'])
def book(bus_id):
    if 'user_id' not in session:
        return redirect(url_for('login'))
    form = BookingForm()
    bus = Bus.query.get(bus_id)
    if form.validate_on_submit():
        booking = Booking(user_id=session['user_id'], bus_id=bus_id, seats_booked=form.seats_booked.data)
        bus.available_seats -= form.seats_booked.data
        db.session.add(booking)
        db.session.commit()
        flash('Booking successful! Proceed to payment.', 'success')
        return redirect(url_for('payment', booking_id=booking.id))
    return render_template('booking.html', form=form, bus=bus)
@app.route('/payment/<int:booking_id>', methods=['GET', 'POST'])
def payment(booking_id):
    if 'user_id' not in session:
        return redirect(url_for('login'))
    form = PaymentForm()
    booking = Booking.query.get(booking_id)
    if form.validate_on_submit():
        payment = Payment(booking_id=booking.id, amount=form.amount.data, status='Completed')
        db.session.add(payment)
        db.session.commit()
        flash('Payment successful!', 'success')
        return redirect(url_for('dashboard'))
    return render_template('payment.html', form=form, booking=booking)
if __name__ == '__main__':
    with app.app_context():
        db.create_all()
    app.run(debug=True)

models.py


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(50), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    bookings = db.relationship('Booking', backref='user', lazy=True)
class Bus(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    total_seats = db.Column(db.Integer, nullable=False)
    available_seats = db.Column(db.Integer, nullable=False)
    route_id = db.Column(db.Integer, db.ForeignKey('route.id'), nullable=False)
    bookings = db.relationship('Booking', backref='bus', lazy=True)
class Route(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    source = db.Column(db.String(100), nullable=False)
    destination = db.Column(db.String(100), nullable=False)
    distance = db.Column(db.Float, nullable=False)
    buses = db.relationship('Bus', backref='route', lazy=True)
class Booking(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    bus_id = db.Column(db.Integer, db.ForeignKey('bus.id'), nullable=False)
    seats_booked = db.Column(db.Integer, nullable=False)
    booking_date = db.Column(db.DateTime, default=datetime.utcnow)
    payment = db.relationship('Payment', backref='booking', uselist=False)
class Payment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    booking_id = db.Column(db.Integer, db.ForeignKey('booking.id'), nullable=False)
    amount = db.Column(db.Float, nullable=False)
    payment_date = db.Column(db.DateTime, default=datetime.utcnow)
    status = db.Column(db.String(20), default='Pending')

forms.py


from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, IntegerField, FloatField, SubmitField
from wtforms.validators import DataRequired, Email, Length, NumberRange
class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=50)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=200)])
    submit = SubmitField('Register')
class LoginForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')
class BookingForm(FlaskForm):
    seats_booked = IntegerField('Seats to Book', validators=[DataRequired(), NumberRange(min=1)])
    submit = SubmitField('Book Now')
class PaymentForm(FlaskForm):
    amount = FloatField('Amount', validators=[DataRequired(), NumberRange(min=0.01)])
    submit = SubmitField('Pay Now')

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>{% block title %}Bus Booking 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') }}`>Bus Booking</a>
            <div class=`collapse navbar-collapse`>
                <ul class=`navbar-nav me-auto`>
                    <li class=`nav-item`>
                        <a class=`nav-link` href=`{{ url_for('search_buses') }}`>Search Buses</a>
                    </li>
                    {% if 'user_id' in session %}
                    <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('logout') }}`>Logout</a>
                    </li>
                    {% else %}
                    <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>
                    {% endif %}
                </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 %}
                        {{ 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>

templates/index.html


{% extends 'base.html' %}
{% block content %}
<h1>Welcome to the Bus Booking System</h1>
<p>Find and book your bus tickets easily!</p>
<a href=`{{ url_for('search_buses') }}` class=`btn btn-primary`>Search Buses</a>
{% endblock %}

templates/search_buses.html


{% extends 'base.html' %}
{% block content %}
<h2>Search Buses</h2>
<form method=`POST`>
    <div class=`mb-3`>
        <label for=`source` class=`form-label`>Source</label>
        <input type=`text` class=`form-control` name=`source` required>
    </div>
    <div class=`mb-3`>
        <label for=`destination` class=`form-label`>Destination</label>
        <input type=`text` class=`form-control` name=`destination` required>
    </div>
    <button type=`submit` class=`btn btn-primary`>Search</button>
</form>
{% if buses %}
<h3>Available Buses</h3>
<ul class=`list-group mt-3`>
    {% for bus in buses %}
    <li class=`list-group-item`>
        {{ bus.name }} - Available Seats: {{ bus.available_seats }}
        <a href=`{{ url_for('book', bus_id=bus.id) }}` class=`btn btn-success btn-sm float-end`>Book Now</a>
    </li>
    {% endfor %}
</ul>
{% endif %}
{% endblock %}

templates/booking.html


{% extends 'base.html' %}
{% block content %}
<h2>Booking for {{ bus.name }}</h2>
<form method=`POST`>
    {{ form.hidden_tag() }}
    <div class=`mb-3`>
        {{ form.seats_booked.label(class=`form-label`) }}
        {{ form.seats_booked(class=`form-control`) }}
    </div>
    {{ form.submit(class=`btn btn-primary`) }}
</form>
{% endblock %}

templates/payment.html


{% extends 'base.html' %}
{% block content %}
<h2>Payment for Booking ID: {{ booking.id }}</h2>
<p>Amount: ${{ booking.seats_booked * 10 }} (Assuming $10 per seat)</p>
<form method=`POST`>
    {{ form.hidden_tag() }}
    <div class=`mb-3`>
        {{ form.amount.label(class=`form-label`) }}
        {{ form.amount(class=`form-control`) }}
    </div>
    {{ form.submit(class=`btn btn-primary`) }}
</form>
{% endblock %}

templates/dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Dashboard</h2>
<p>Welcome, {{ user.username }}!</p>
<h3>Your Bookings</h3>
<ul class=`list-group`>
    {% for booking in user.bookings %}
    <li class=`list-group-item`>
        Booking ID: {{ booking.id }} - Bus: {{ booking.bus.name }} - Seats: {{ booking.seats_booked }}
    </li>
    {% endfor %}
</ul>
{% endblock %}

templates/admin/add_bus.html


{% extends 'base.html' %}
{% block content %}
<h2>Add New Bus</h2>
<form method=`POST`>
    <div class=`mb-3`>
        <label for=`name` class=`form-label`>Bus Name</label>
        <input type=`text` class=`form-control` name=`name` required>
    </div>
    <div class=`mb-3`>
        <label for=`total_seats` class=`form-label`>Total Seats</label>
        <input type=`number` class=`form-control` name=`total_seats` required>
    </div>
    <div class=`mb-3`>
        <label for=`route_id` class=`form-label`>Route ID</label>
        <input type=`number` class=`form-control` name=`route_id` required>
    </div>
    <button type=`submit` class=`btn btn-primary`>Add Bus</button>
</form>
{% endblock %}

templates/admin/manage_buses.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Buses</h2>
<table class=`table`>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Total Seats</th>
            <th>Available Seats</th>
            <th>Route</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        {% for bus in buses %}
        <tr>
            <td>{{ bus.id }}</td>
            <td>{{ bus.name }}</td>
            <td>{{ bus.total_seats }}</td>
            <td>{{ bus.available_seats }}</td>
            <td>{{ bus.route.source }} to {{ bus.route.destination }}</td>
            <td>
                <a href=`{{ url_for('edit_bus', bus_id=bus.id) }}` class=`btn btn-warning btn-sm`>Edit</a>
                <a href=`{{ url_for('delete_bus', bus_id=bus.id) }}` class=`btn btn-danger btn-sm`>Delete</a>
            </td>
        </tr>
        {% endfor %}
    </tbody>
</table>
{% endblock %}

templates/admin/manage_routes.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Routes</h2>
<table class=`table`>
    <thead>
        <tr>
            <th>ID</th>
            <th>Source</th>
            <th>Destination</th>
            <th>Distance (km)</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        {% for route in routes %}
        <tr>
            <td>{{ route.id }}</td>
            <td>{{ route.source }}</td>
            <td>{{ route.destination }}</td>
            <td>{{ route.distance }}</td>
            <td>
                <a href=`{{ url_for('edit_route', route_id=route.id) }}` class=`btn btn-warning btn-sm`>Edit</a>
                <a href=`{{ url_for('delete_route', route_id=route.id) }}` class=`btn btn-danger btn-sm`>Delete</a>
            </td>
        </tr>
        {% endfor %}
    </tbody>
</table>
{% endblock %}

Conclusion

This structure provides a comprehensive foundation for a Car Sales and Inventory Store project using Flask and Bootstrap 5. You can expand upon this by adding features such as search functionality, user permissions, and more advanced reporting.

Written by Surfside Media

Senior Full Stack Developer specializing in Web Technologies.