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.
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
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."
Core Features Required
- User registration with email validation
- Secure login with password hashing
- Session management with Flask-Login
- Password reset functionality
- SQLite database with SQLAlchemy ORM
- User, Movie, and Favorite models
- CRUD operations for movies
- Relationships between tables
- Responsive Bootstrap templates
- Movie listing with pagination
- Search and filter functionality
- User profile and favorites page
- Environment-based configuration
- Production-ready settings
- Cloud deployment (Render/Railway)
- HTTPS and security headers
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 Schema
| Column | Type | Description |
|---|---|---|
budget | Integer | Production budget in USD |
genres | JSON | List of genre objects [{id, name}] |
homepage | String | Official movie website URL |
id | Integer | Unique movie identifier from TMDB |
keywords | JSON | List of keyword objects [{id, name}] |
original_language | String | Original language code (e.g., en, fr) |
original_title | String | Original movie title |
overview | String | Brief description/synopsis |
popularity | Decimal | Popularity score |
production_companies | JSON | List of production company objects |
production_countries | JSON | List of country objects |
release_date | Date | Release date (YYYY-MM-DD) |
revenue | Integer | Box office revenue in USD |
runtime | Integer | Duration in minutes |
spoken_languages | JSON | List of language objects |
status | String | Released, Post Production, etc. |
tagline | String | Movie tagline/slogan |
title | String | Movie title |
vote_average | Decimal | Average rating (0.0-10.0) |
vote_count | Integer | Number of votes |
| Column | Type | Description |
|---|---|---|
movie_id | Integer | Movie ID (foreign key to movies.id) |
title | String | Movie title |
cast | JSON | List of cast members [{character, name, order, ...}] |
crew | JSON | List of crew members [{job, name, department, ...}] |
Sample Data Preview
Here is sample data from the TMDB dataset:
| title | release_date | budget | revenue | vote_average | runtime |
|---|---|---|---|---|---|
| Avatar | 2009-12-10 | $237M | $2.79B | 7.2 | 162 min |
| Pirates of the Caribbean: At World's End | 2007-05-19 | $300M | $961M | 6.9 | 169 min |
| The Dark Knight | 2008-07-16 | $185M | $1.0B | 8.3 | 152 min |
Project Requirements
Your project must include all of the following components. Structure your code with Flask blueprints, proper configuration, and follow Flask best practices.
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
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)
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)
RESTful API Endpoints
Create JSON API endpoints:
GET /api/movies- List all movies (with pagination)GET /api/movies/<id>- Get single movie by IDPOST /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
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
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
}
Feature Specifications
Implement the following features with proper error handling. Each feature should be testable independently.
- 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
- Login with email or username
- Password verification
- Remember me checkbox
- Session management (Flask-Login)
- Redirect to original page after login
- Invalid credentials error handling
- 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
- 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
- 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
- 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>
Deployment Guide
Deploy your Flask application to a cloud platform. We recommend Render or Railway for free Python hosting.
- Create account at render.com
- Connect your GitHub repository
- Create new "Web Service"
- Set environment variables:
SECRET_KEYFLASK_ENV=production
- Set build command:
pip install -r requirements.txt - Set start command:
gunicorn run:app - Deploy and get your URL!
- Create account at railway.app
- Create new project from GitHub
- Railway auto-detects Python
- Add environment variables in dashboard
- Railway auto-deploys on push
- Optional: Add PostgreSQL plugin
- Get your
.railway.appURL
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
Submission Requirements
Create a public GitHub repository with the exact name shown below:
Required Repository Name
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
Enter your GitHub username - we will verify your repository automatically
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)
Reviews system - users can rate and review movies
Admin dashboard - manage users and movies
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