Capstone Project 3

Flask Web Application

Build a full-stack movie database web application using Flask. Implement user authentication with secure password hashing, perform CRUD operations with SQLite/SQLAlchemy, create RESTful API endpoints, and deploy your application to the cloud.

12-15 hours
Intermediate-Advanced
500 Points
What You Will Build
  • User authentication system
  • SQLite database with SQLAlchemy
  • RESTful API endpoints
  • Movie CRUD operations
  • Cloud deployment (Render/Railway)
Contents
01

Project Overview

Build a production-ready Flask web application that demonstrates full-stack development skills. Your application will serve as a movie database where users can register, log in, browse movies, add favorites, write reviews, and manage their profiles. The backend will feature RESTful APIs, secure authentication, and database persistence.

Skills Applied: This project tests your proficiency in Flask framework, SQLAlchemy ORM, user authentication (Flask-Login, Werkzeug), Jinja2 templating, RESTful API design, and cloud deployment.

What You Will Build

A fully functional movie database web application:

$ python app.py

 * Serving Flask app 'app'
 * Debug mode: on
 * Running on http://127.0.0.1:5000

==============================================
     MOVIEHUB - Flask Web Application
==============================================

Available Routes:
  GET  /                     → Home page (movie listings)
  GET  /movies               → All movies (paginated)
  GET  /movies/<id>          → Movie details
  POST /movies               → Add new movie (auth required)
  PUT  /movies/<id>          → Update movie (auth required)
  DELETE /movies/<id>        → Delete movie (auth required)
  
  GET  /auth/register        → Registration page
  POST /auth/register        → Create new user
  GET  /auth/login           → Login page
  POST /auth/login           → Authenticate user
  GET  /auth/logout          → Logout user
  GET  /auth/profile         → User profile (auth required)
  
  GET  /api/movies           → JSON API: List movies
  GET  /api/movies/<id>      → JSON API: Get movie
  POST /api/movies           → JSON API: Create movie

Database: SQLite (movies.db)
Users: 0 registered
Movies: 5000 loaded from TMDB dataset

[INFO] Application ready!

Skills You Will Apply

Flask Framework

Routes, blueprints, templates, forms, and configuration

Authentication

User registration, login, sessions, password hashing

Database

SQLite, SQLAlchemy ORM, migrations, relationships

Deployment

Environment variables, production config, cloud hosting

Learning Objectives

Technical Skills
  • Build web applications with Flask framework
  • Design and implement database models with SQLAlchemy
  • Create secure user authentication systems
  • Build RESTful API endpoints with JSON responses
  • Deploy applications to cloud platforms
Professional Skills
  • Follow MVC architecture patterns
  • Handle user input validation securely
  • Implement proper error handling
  • Write clean, maintainable code
  • Configure production environments
Ready to submit? Already completed the project? Submit your work now!
Submit Now
02

Project Scenario

CineTrack Studios

You have been hired as a Full-Stack Python Developer at CineTrack Studios, a movie review and recommendation startup. The company needs a web application where users can browse movies, create accounts, save favorites, and write reviews. The application should have both a user-friendly web interface and a RESTful API for mobile app integration.

"We need a robust web application built with Flask. Users should be able to register, log in securely, browse our movie database, and manage their favorites. We also need API endpoints for our upcoming mobile app. The app should be deployed to the cloud and ready for production use."

Maya Chen, Product Manager

Core Features Required

Authentication
  • User registration with email validation
  • Secure login with password hashing
  • Session management with Flask-Login
  • Password reset functionality
Database Operations
  • SQLite database with SQLAlchemy ORM
  • User, Movie, and Favorite models
  • CRUD operations for movies
  • Relationships between tables
Web Interface
  • Responsive Bootstrap templates
  • Movie listing with pagination
  • Search and filter functionality
  • User profile and favorites page
Deployment
  • Environment-based configuration
  • Production-ready settings
  • Cloud deployment (Render/Railway)
  • HTTPS and security headers
Dataset: Use the TMDB 5000 Movie Dataset from Kaggle - a comprehensive dataset with 5000 movies including titles, ratings, budgets, revenues, and more!
03

The Dataset

Your application will use the TMDB 5000 Movie Dataset - one of the most popular movie datasets on Kaggle. This real-world dataset provides comprehensive movie information perfect for building a movie database application.

Dataset Download

Download the TMDB 5000 dataset files (from Kaggle) to seed your database with real movie data. The dataset includes two CSV files - movies metadata and credits.

Original Data Source

This project uses the TMDB 5000 Movie Dataset from Kaggle - a comprehensive dataset containing metadata on approximately 5000 movies from The Movie Database. The dataset includes budget, revenue, runtime, genres, production companies, and more.

Dataset Info: ~5000 movies | 2 files (movies & credits) | 45.74 MB total | Views: 2.16M | Downloads: 500K+ | Usability: 8.24 | Source: The Movie Database (TMDb)
Dataset Schema

ColumnTypeDescription
budgetIntegerProduction budget in USD
genresJSONList of genre objects [{id, name}]
homepageStringOfficial movie website URL
idIntegerUnique movie identifier from TMDB
keywordsJSONList of keyword objects [{id, name}]
original_languageStringOriginal language code (e.g., en, fr)
original_titleStringOriginal movie title
overviewStringBrief description/synopsis
popularityDecimalPopularity score
production_companiesJSONList of production company objects
production_countriesJSONList of country objects
release_dateDateRelease date (YYYY-MM-DD)
revenueIntegerBox office revenue in USD
runtimeIntegerDuration in minutes
spoken_languagesJSONList of language objects
statusStringReleased, Post Production, etc.
taglineStringMovie tagline/slogan
titleStringMovie title
vote_averageDecimalAverage rating (0.0-10.0)
vote_countIntegerNumber of votes

ColumnTypeDescription
movie_idIntegerMovie ID (foreign key to movies.id)
titleStringMovie title
castJSONList of cast members [{character, name, order, ...}]
crewJSONList of crew members [{job, name, department, ...}]
Sample Data Preview

Here is sample data from the TMDB dataset:

titlerelease_datebudgetrevenuevote_averageruntime
Avatar2009-12-10$237M$2.79B7.2162 min
Pirates of the Caribbean: At World's End2007-05-19$300M$961M6.9169 min
The Dark Knight2008-07-16$185M$1.0B8.3152 min
Database Seeding: Use the provided CSV to seed your SQLite database. Create a script that loads the movie data into your Movie model when the application starts.
04

Project Requirements

Your project must include all of the following components. Structure your code with Flask blueprints, proper configuration, and follow Flask best practices.

1
Project Structure

Organize your code into the following structure:

flask-moviehub/
├── app/
│   ├── __init__.py          # App factory
│   ├── models.py            # Database models
│   ├── auth/
│   │   ├── __init__.py      # Auth blueprint
│   │   ├── routes.py        # Auth routes
│   │   └── forms.py         # WTForms
│   ├── main/
│   │   ├── __init__.py      # Main blueprint
│   │   └── routes.py        # Main routes
│   ├── api/
│   │   ├── __init__.py      # API blueprint
│   │   └── routes.py        # API endpoints
│   ├── templates/
│   │   ├── base.html        # Base template
│   │   ├── auth/            # Auth templates
│   │   └── main/            # Main templates
│   └── static/
│       ├── css/             # Stylesheets
│       └── js/              # JavaScript
├── migrations/              # Database migrations
├── tests/
│   ├── test_auth.py         # Auth tests
│   ├── test_models.py       # Model tests
│   └── test_api.py          # API tests
├── instance/
│   └── movies.db            # SQLite database
├── config.py                # Configuration
├── requirements.txt         # Dependencies
├── run.py                   # Entry point
└── README.md                # Documentation
Requirement: Use Flask application factory pattern and blueprints to organize your code into modular components.
2
Database Models (SQLAlchemy)

Create the following database models:

  • User: id, username, email, password_hash, created_at
  • Movie: id, title, overview, release_date, budget, revenue, rating, runtime
  • Favorite: id, user_id, movie_id, created_at (many-to-many relationship)
  • Review: id, user_id, movie_id, rating, content, created_at (optional)
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime

db = SQLAlchemy()

# Association table for favorites
favorites = db.Table('favorites',
    db.Column('user_id', db.Integer, db.ForeignKey('users.id'), primary_key=True),
    db.Column('movie_id', db.Integer, db.ForeignKey('movies.id'), primary_key=True),
    db.Column('created_at', db.DateTime, default=datetime.utcnow)
)

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    
    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_hash = db.Column(db.String(256), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    favorites = db.relationship('Movie', secondary=favorites, 
                               backref=db.backref('favorited_by', lazy='dynamic'))
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

class Movie(db.Model):
    __tablename__ = 'movies'
    
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    overview = db.Column(db.Text)
    release_date = db.Column(db.Date)
    budget = db.Column(db.BigInteger, default=0)
    revenue = db.Column(db.BigInteger, default=0)
    runtime = db.Column(db.Integer)
    vote_average = db.Column(db.Float, default=0.0)
    vote_count = db.Column(db.Integer, default=0)
    popularity = db.Column(db.Float, default=0.0)
3
User Authentication (Flask-Login)

Implement secure authentication:

  • Registration: Username, email, password with validation
  • Login: Email/username and password authentication
  • Logout: Clear session and redirect
  • Password hashing: Use Werkzeug's generate_password_hash
  • Protected routes: Use @login_required decorator
  • Sessions: Flask-Login session management
from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, login_required, current_user
from app.models import User, db
from app.auth.forms import LoginForm, RegistrationForm

auth = Blueprint('auth', __name__)

@auth.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Registration successful! Please log in.', 'success')
        return redirect(url_for('auth.login'))
    return render_template('auth/register.html', form=form)

@auth.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.check_password(form.password.data):
            login_user(user, remember=form.remember.data)
            next_page = request.args.get('next')
            flash('Welcome back!', 'success')
            return redirect(next_page or url_for('main.index'))
        flash('Invalid email or password', 'danger')
    return render_template('auth/login.html', form=form)
4
RESTful API Endpoints

Create JSON API endpoints:

  • GET /api/movies - List all movies (with pagination)
  • GET /api/movies/<id> - Get single movie by ID
  • POST /api/movies - Create new movie (auth required)
  • PUT /api/movies/<id> - Update movie (auth required)
  • DELETE /api/movies/<id> - Delete movie (auth required)
  • GET /api/movies/search?q= - Search movies by title
from flask import Blueprint, jsonify, request
from flask_login import login_required, current_user
from app.models import Movie, db

api = Blueprint('api', __name__)

@api.route('/movies', methods=['GET'])
def get_movies():
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 20, type=int)
    
    movies = Movie.query.paginate(page=page, per_page=per_page)
    
    return jsonify({
        'movies': [movie.to_dict() for movie in movies.items],
        'total': movies.total,
        'pages': movies.pages,
        'current_page': page
    })

@api.route('/movies/<int:id>', methods=['GET'])
def get_movie(id):
    movie = Movie.query.get_or_404(id)
    return jsonify(movie.to_dict())

@api.route('/movies', methods=['POST'])
@login_required
def create_movie():
    data = request.get_json()
    
    movie = Movie(
        title=data['title'],
        overview=data.get('overview', ''),
        budget=data.get('budget', 0),
        revenue=data.get('revenue', 0)
    )
    db.session.add(movie)
    db.session.commit()
    
    return jsonify(movie.to_dict()), 201
5
Templates (Jinja2 + Bootstrap)

Create responsive web pages:

  • base.html: Layout with navbar, footer, flash messages
  • index.html: Home page with featured movies
  • movies.html: Movie grid with pagination
  • movie_detail.html: Single movie details
  • login.html / register.html: Auth forms
  • profile.html: User profile with favorites
Requirement: Use Bootstrap 5 for responsive design and Jinja2 template inheritance with a base template.
6
Configuration

Environment-based configuration:

  • Development: Debug mode, SQLite, verbose logging
  • Production: No debug, secure cookies, HTTPS
  • Environment variables: SECRET_KEY, DATABASE_URL
  • .env file: Local environment variables
import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///instance/movies.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False
    # Use PostgreSQL in production
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}
05

Feature Specifications

Implement the following features with proper error handling. Each feature should be testable independently.

User Registration
  • Username (3-20 characters, unique)
  • Email validation (unique)
  • Password (8+ chars, hashed with Werkzeug)
  • Confirm password matching
  • Flash success/error messages
  • Redirect to login after registration
User Login
  • Login with email or username
  • Password verification
  • Remember me checkbox
  • Session management (Flask-Login)
  • Redirect to original page after login
  • Invalid credentials error handling
Movie Browsing
  • Grid display with movie cards
  • Pagination (20 per page)
  • Search by title
  • Filter by genre/year
  • Sort by rating/date/popularity
  • Movie detail page with full info
Favorites System
  • Add movie to favorites (auth required)
  • Remove from favorites
  • View all favorites on profile
  • Toggle favorite button on movie cards
  • Count total favorites
  • AJAX/fetch for instant updates
REST API
  • JSON responses for all endpoints
  • Proper HTTP status codes
  • Pagination in list endpoints
  • Error responses with messages
  • Authentication for write operations
  • API documentation in README
User Profile
  • Display username and email
  • Member since date
  • List of favorite movies
  • Total favorites count
  • Update profile option (bonus)
  • Change password option (bonus)
Sample Pages
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}MovieHub{% endblock %}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="{{ url_for('main.index') }}">🎬 MovieHub</a>
            <div class="navbar-nav ms-auto">
                {% if current_user.is_authenticated %}
                    <a class="nav-link" href="{{ url_for('main.profile') }}">{{ current_user.username }}</a>
                    <a class="nav-link" href="{{ url_for('auth.logout') }}">Logout</a>
                {% else %}
                    <a class="nav-link" href="{{ url_for('auth.login') }}">Login</a>
                    <a class="nav-link" href="{{ url_for('auth.register') }}">Register</a>
                {% endif %}
            </div>
        </div>
    </nav>
    
    <main class="container my-4">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% for category, message in messages %}
                <div class="alert alert-{{ category }}">{{ message }}</div>
            {% endfor %}
        {% endwith %}
        
        {% block content %}{% endblock %}
    </main>
</body>
</html>
06

Deployment Guide

Deploy your Flask application to a cloud platform. We recommend Render or Railway for free Python hosting.

Option 1: Render (Recommended)
  1. Create account at render.com
  2. Connect your GitHub repository
  3. Create new "Web Service"
  4. Set environment variables:
    • SECRET_KEY
    • FLASK_ENV=production
  5. Set build command: pip install -r requirements.txt
  6. Set start command: gunicorn run:app
  7. Deploy and get your URL!
Option 2: Railway
  1. Create account at railway.app
  2. Create new project from GitHub
  3. Railway auto-detects Python
  4. Add environment variables in dashboard
  5. Railway auto-deploys on push
  6. Optional: Add PostgreSQL plugin
  7. Get your .railway.app URL
Required Files for Deployment
# requirements.txt
Flask==3.0.0
Flask-SQLAlchemy==3.1.1
Flask-Login==0.6.3
Flask-WTF==1.2.1
Werkzeug==3.0.1
python-dotenv==1.0.0
gunicorn==21.2.0
email-validator==2.1.0
# run.py (entry point for production)
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run()
# Procfile (for Render/Heroku)
web: gunicorn run:app
Important: Include your deployed URL in your README.md. Your application must be live and accessible for full points on the deployment requirement.
07

Submission Requirements

Create a public GitHub repository with the exact name shown below:

Required Repository Name
python-flask-moviehub
github.com/<your-username>/python-flask-moviehub
Required Project Structure
python-flask-moviehub/
├── app/
│   ├── __init__.py          # App factory
│   ├── models.py            # Database models
│   ├── auth/                # Auth blueprint
│   ├── main/                # Main blueprint
│   ├── api/                 # API blueprint
│   ├── templates/           # Jinja2 templates
│   └── static/              # CSS, JS, images
├── data/
│   ├── tmdb_5000_movies.csv    # Kaggle dataset (movies)
│   └── tmdb_5000_credits.csv   # Kaggle dataset (credits)
├── tests/                   # Unit tests
├── screenshots/
│   ├── home.png             # Home page
│   ├── login.png            # Login page
│   ├── movies.png           # Movies listing
│   └── deployed.png         # Live deployment
├── config.py                # Configuration
├── requirements.txt         # Dependencies
├── run.py                   # Entry point
├── Procfile                 # Deployment config
└── README.md                # Documentation
README.md Required Sections
1. Project Header
  • Project title and badges
  • Live demo URL
  • Your name and submission date
2. Features
  • List all implemented features
  • Technologies used
  • Screenshots with descriptions
3. Installation
  • Clone and setup instructions
  • Environment variables
  • Database initialization
4. Usage
  • How to run the server
  • Default routes overview
  • Test accounts (optional)
5. API Documentation
  • All API endpoints
  • Request/response examples
  • Authentication requirements
6. Project Structure
  • Folder organization
  • Blueprint explanations
7. Deployment
  • Deployed URL (required)
  • Deployment platform used
8. Database Schema
  • ER diagram (optional)
  • Model descriptions
Do Include
  • All Python modules with docstrings
  • Sample movie data CSV file
  • Unit tests for core functionality
  • Screenshots of the application
  • requirements.txt with all dependencies
  • Live deployment URL
Do Not Include
  • __pycache__ folders
  • Virtual environment folder
  • instance/ folder with database
  • .env file with secrets
  • Large media files
  • IDE configuration files
Submit Your Project

Enter your GitHub username - we will verify your repository automatically

08

Grading Rubric

Your project will be graded on the following criteria. Total: 500 points.

Criteria Points Description
Authentication 80 Registration, login, logout, password hashing, protected routes
Database Models 80 SQLAlchemy models, relationships, CRUD operations
API Endpoints 70 RESTful design, JSON responses, proper status codes
Templates/UI 60 Jinja2 templates, Bootstrap styling, responsive design
Features 60 Favorites, search, pagination, movie details
Deployment 50 Live URL working, proper configuration
Code Quality 50 Structure, blueprints, error handling, clean code
Documentation 50 README, API docs, screenshots, setup instructions
Total 500
Grading Levels
Excellent

450-500

90%+
Good

375-449

75-89%
Satisfactory

300-374

60-74%
Needs Work

<300

<60%
Bonus Points (up to 75 extra)
+25 points

Reviews system - users can rate and review movies

+25 points

Admin dashboard - manage users and movies

+25 points

OAuth login - Google or GitHub authentication

Ready to Submit?

Make sure you have completed all requirements, deployed your app, and reviewed the grading rubric above.

Submit Project