Flask Projects With Source Code

Online Voting System Project In Flask


Creating an advanced-level Online Voting System using Flask and Bootstrap 5 involves designing a robust database structure, implementing Flask routes, and creating responsive and interactive web pages. Below is a detailed guide:

1. Database Structure

The database will store users, candidates, elections, votes, and other related data. We'll use SQLAlchemy (an ORM for Flask) to manage the database.

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(50), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    votes = db.relationship('Vote', backref='user', lazy=True)
class Candidate(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    party = db.Column(db.String(100), nullable=False)
    election_id = db.Column(db.Integer, db.ForeignKey('election.id'), nullable=False)
    votes = db.relationship('Vote', backref='candidate', lazy=True)
class Election(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    start_date = db.Column(db.DateTime, nullable=False)
    end_date = db.Column(db.DateTime, nullable=False)
    candidates = db.relationship('Candidate', backref='election', lazy=True)
    votes = db.relationship('Vote', backref='election', lazy=True)
class Vote(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    candidate_id = db.Column(db.Integer, db.ForeignKey('candidate.id'), nullable=False)
    election_id = db.Column(db.Integer, db.ForeignKey('election.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

2. Flask Application Structure

Organize the project into the following structure:


online_voting_system/
│
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes/
│   │   ├── auth.py
│   │   ├── elections.py
│   │   ├── candidates.py
│   │   ├── votes.py
│   │   └── main.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── index.html
│   │   ├── login.html
│   │   ├── register.html
│   │   ├── dashboard.html
│   │   ├── add_election.html
│   │   ├── add_candidate.html
│   │   ├── vote.html
│   │   └── results.html
│   ├── static/
│   │   ├── css/
│   │   │   └── styles.css
│   │   └── js/
│   │       └── scripts.js
│   └── utils.py
│
├── config.py
├── requirements.txt
└── run.py

3. Flask Application Code

app/__init__.py


from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
db = SQLAlchemy()
login_manager = LoginManager()
def create_app():
    app = Flask(__name__)
    app.config.from_pyfile('config.py')
    db.init_app(app)
    login_manager.init_app(app)
    login_manager.login_view = 'auth.login'
    from .routes.auth import auth_bp
    from .routes.elections import elections_bp
    from .routes.candidates import candidates_bp
    from .routes.votes import votes_bp
    from .routes.main import main_bp
    app.register_blueprint(auth_bp)
    app.register_blueprint(elections_bp)
    app.register_blueprint(candidates_bp)
    app.register_blueprint(votes_bp)
    app.register_blueprint(main_bp)
    return app

config.py


import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'your-secret-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 
        'sqlite:///' + os.path.join(basedir, 'online_voting_system.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

run.py


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

4. Flask Routes

routes/auth.py


from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_user, logout_user, login_required, current_user
from .forms import LoginForm, RegistrationForm
from ..models import User, db
auth_bp = Blueprint('auth', __name__)
@auth_bp.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.verify_password(form.password.data):
            login_user(user)
            return redirect(url_for('main.dashboard'))
        flash('Invalid email or password.')
    return render_template('login.html', form=form)
@auth_bp.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('auth.login'))
@auth_bp.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! You can now log in.')
        return redirect(url_for('auth.login'))
    return render_template('register.html', form=form)

routes/elections.py


from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_required
from ..models import Election, db
from ..forms import ElectionForm
elections_bp = Blueprint('elections', __name__)
@elections_bp.route('/add_election', methods=['GET', 'POST'])
@login_required
def add_election():
    form = ElectionForm()
    if form.validate_on_submit():
        election = Election(name=form.name.data, start_date=form.start_date.data, end_date=form.end_date.data)
        db.session.add(election)
        db.session.commit()
        flash('Election added successfully!')
        return redirect(url_for('main.dashboard'))
    return render_template('add_election.html', form=form)
@elections_bp.route('/elections')
@login_required
def view_elections():
    elections = Election.query.all()
    return render_template('view_elections.html', elections=elections)

routes/candidates.py


from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_required
from ..models import Candidate, Election, db
from ..forms import CandidateForm
candidates_bp = Blueprint('candidates', __name__)
@candidates_bp.route('/add_candidate', methods=['GET', 'POST'])
@login_required
def add_candidate():
    form = CandidateForm()
    form.election.choices = [(e.id, e.name) for e in Election.query.all()]
    if form.validate_on_submit():
        candidate = Candidate(name=form.name.data, party=form.party.data, election_id=form.election.data)
        db.session.add(candidate)
        db.session.commit()
        flash('Candidate added successfully!')
        return redirect(url_for('main.dashboard'))
    return render_template('add_candidate.html', form=form)
@candidates_bp.route('/candidates')
@login_required
def view_candidates():
    candidates = Candidate.query.all()
    return render_template('view_candidates.html', candidates=candidates)

routes/votes.py


from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_required, current_user
from ..models import Vote, Candidate, Election, db
from ..forms import VoteForm
votes_bp = Blueprint('votes', __name__)
@votes_bp.route('/vote/<int:election_id>', methods=['GET', 'POST'])
@login_required
def vote(election_id):
    election = Election.query.get_or_404(election_id)
    candidates = Candidate.query.filter_by(election_id=election.id).all()
    form = VoteForm()
    form.candidate.choices = [(c.id, c.name) for c in candidates]
    if form.validate_on_submit():
        if Vote.query.filter_by(user_id=current_user.id, election_id=election.id).first():
            flash('You have already voted in this election.')
            return redirect(url_for('main.dashboard'))
        vote = Vote(user_id=current_user.id, candidate_id=form.candidate.data, election_id=election.id)
        db.session.add(vote)
        db.session.commit()
        flash('Vote cast successfully!')
        return redirect(url_for('main.dashboard'))
    return render_template('vote.html', election=election, form=form, candidates=candidates)
@votes_bp.route('/results/<int:election_id>')
@login_required
def results(election_id):
    election = Election.query.get_or_404(election_id)
    results = db.session.query(Candidate, db.func.count(Vote.id)).outerjoin(Vote).filter(Candidate.election_id == election.id).group_by(Candidate.id).all()
    return render_template('results.html', election=election, results=results)

routes/main.py


from flask import Blueprint, render_template
from flask_login import login_required
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def index():
    return render_template('index.html')
@main_bp.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html')

5. HTML Templates with Bootstrap 5

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 %}Online Voting 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('main.index') }}`>Online Voting System</a>
            <div class=`collapse navbar-collapse`>
                <ul class=`navbar-nav me-auto`>
                    {% if current_user.is_authenticated %}
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('main.dashboard') }}`>Dashboard</a>
                        </li>
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('elections.view_elections') }}`>View Elections</a>
                        </li>
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('candidates.view_candidates') }}`>View Candidates</a>
                        </li>
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('votes.vote', election_id=1) }}`>Vote</a>
                        </li>
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('auth.logout') }}`>Logout</a>
                        </li>
                    {% else %}
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('auth.login') }}`>Login</a>
                        </li>
                        <li class=`nav-item`>
                            <a class=`nav-link` href=`{{ url_for('auth.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 %}
                        <p>{{ message }}</p>
                    {% 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 title %}Home{% endblock %}
{% block content %}
<h1>Welcome to the Online Voting System</h1>
<p>Participate in elections and make your voice heard!</p>
{% endblock %}

templates/login.html


{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% 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>
    <button type=`submit` class=`btn btn-primary`>Login</button>
</form>
{% endblock %}

templates/register.html


{% extends 'base.html' %}
{% block title %}Register{% endblock %}
{% 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>
    <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_election.html


{% extends 'base.html' %}
{% block title %}Add Election{% endblock %}
{% block content %}
<h2>Add Election</h2>
<form method=`POST`>
    {{ form.hidden_tag() }}
    <div class=`mb-3`>
        {{ form.name.label(class=`form-label`) }}
        {{ form.name(class=`form-control`) }}
    </div>
    <div class=`mb-3`>
        {{ form.start_date.label(class=`form-label`) }}
        {{ form.start_date(class=`form-control`) }}
    </div>
    <div class=`mb-3`>
        {{ form.end_date.label(class=`form-label`) }}
        {{ form.end_date(class=`form-control`) }}
    </div>
    <button type=`submit` class=`btn btn-primary`>Add Election</button>
</form>
{% endblock %}

templates/add_candidate.html


{% extends 'base.html' %}
{% block title %}Add Candidate{% endblock %}
{% block content %}
<h2>Add Candidate</h2>
<form method=`POST`>
    {{ form.hidden_tag() }}
    <div class=`mb-3`>
        {{ form.name.label(class=`form-label`) }}
        {{ form.name(class=`form-control`) }}
    </div>
    <div class=`mb-3`>
        {{ form.party.label(class=`form-label`) }}
        {{ form.party(class=`form-control`) }}
    </div>
    <div class=`mb-3`>
        {{ form.election.label(class=`form-label`) }}
        {{ form.election(class=`form-control`) }}
    </div>
    <button type=`submit` class=`btn btn-primary`>Add Candidate</button>
</form>
{% endblock %}

templates/vote.html


{% extends 'base.html' %}
{% block title %}Vote{% endblock %}
{% block content %}
<h2>Vote for {{ election.name }}</h2>
<form method=`POST`>
    {{ form.hidden_tag() }}
    <div class=`mb-3`>
        {{ form.candidate.label(class=`form-label`) }}
        {{ form.candidate(class=`form-control`) }}
    </div>
    <button type=`submit` class=`btn btn-primary`>Cast Vote</button>
</form>
{% endblock %}

templates/results.html


{% extends 'base.html' %}
{% block title %}Election Results{% endblock %}
{% block content %}
<h2>Results for {{ election.name }}</h2>
<table class=`table`>
    <thead>
        <tr>
            <th scope=`col`>Candidate</th>
            <th scope=`col`>Votes</th>
        </tr>
    </thead>
    <tbody>
        {% for candidate, vote_count in results %}
        <tr>
            <td>{{ candidate.name }}</td>
            <td>{{ vote_count }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>
{% endblock %}

6. Forms for Flask-WTF

forms.py


from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, DateTimeField, 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 ElectionForm(FlaskForm):
    name = StringField('Election Name', validators=[DataRequired()])
    start_date = DateTimeField('Start Date', format='%Y-%m-%d %H:%M:%S', validators=[DataRequired()])
    end_date = DateTimeField('End Date', format='%Y-%m-%d %H:%M:%S', validators=[DataRequired()])
    submit = SubmitField('Add Election')
class CandidateForm(FlaskForm):
    name = StringField('Candidate Name', validators=[DataRequired()])
    party = StringField('Party', validators=[DataRequired()])
    election = SelectField('Election', coerce=int, validators=[DataRequired()])
    submit = SubmitField('Add Candidate')
class VoteForm(FlaskForm):
    candidate = SelectField('Candidate', coerce=int, validators=[DataRequired()])
    submit = SubmitField('Vote')

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 Online Voting System using Flask and Bootstrap 5, allowing for user authentication, election management, candidate management, and voting functionality.

Written by Surfside Media

Senior Full Stack Developer specializing in Web Technologies.