An intelligent movie recommendation system built with Django, featuring machine learning-powered recommendations, external API integrations, and a beautiful dark-themed UI.
- Features
- External Integrations
- Python Topics Demonstrated
- Project Structure
- Installation
- API Configuration
- Usage
- API Overview
- Topic Locations Reference
- π― Smart Movie Recommendations - ML-powered personalized suggestions using Ridge Regression
- β Rating System - Rate movies and get tailored recommendations
- π Advanced Search - Search by title, genre, director, or year
- π Analytics Dashboard - Comprehensive statistics with interactive Matplotlib charts
- π€ User Profiles - Track your movie journey and preferences
- π₯οΈ Desktop GUI - Tkinter-based desktop client for offline use
- π Dark Theme Design - Sleek dark color palette with amber accents
- β¨ Smooth Animations - Page transitions, staggered card loading, hover effects
- π± Responsive Layout - Works on all devices with Bootstrap 5.3
- π¨ Glassmorphism Effects - Modern backdrop blur styling
The system integrates with the Open Movie Database (OMDB) API to fetch rich metadata from IMDB:
| Feature | Description |
|---|---|
| Movie Posters | High-quality movie artwork from IMDB |
| IMDB Ratings | Official ratings and vote counts |
| Rotten Tomatoes | Critical consensus ratings |
| Metacritic Scores | Aggregated critic reviews |
| Cast & Crew | Director and main cast information |
| Box Office Data | Revenue and budget information |
| Awards | Oscar nominations and wins |
| Plot Summaries | Detailed movie descriptions |
# Example: Fetching IMDB data
from movies.services.external_apis import OMDBClient
client = OMDBClient()
movie_data = client.get_movie_by_title("Inception")
# Returns: poster_url, imdb_rating, rotten_tomatoes, metacritic, director, actors, etc.Direct integration with Letterboxd - the social network for film lovers:
| Feature | Description |
|---|---|
| Movie Pages | Direct links to Letterboxd movie entries |
| Diary Logging | Log films to your Letterboxd diary |
| Watchlist | Add movies to your Letterboxd watchlist |
| Social Features | Access reviews and community ratings |
# Example: Getting Letterboxd URLs
from movies.services.external_apis import LetterboxdClient
client = LetterboxdClient()
urls = client.get_movie_urls("Inception", 2010)
# Returns: film_url, diary_url, watchlist_urlβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CineSense App β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
β β OMDBClient β β LetterboxdClient β β
β β (external_apis)β β (external_apis) β β
β ββββββββββ¬βββββββββ βββββββββββββ¬ββββββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
β β OMDB REST API β β Letterboxd URLs β β
β β (api.omdbapi) β β (letterboxd.com) β β
β ββββββββββ¬βββββββββ βββββββββββββ¬ββββββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
β β IMDB Database β β Letterboxd Platform β β
β βββββββββββββββββββ βββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
This project demonstrates ALL of the following Python concepts:
| Topic | Location | Description |
|---|---|---|
| Casting | forms.py, cli_tools/, tkinter_client/ |
int(), float(), str() conversions |
| Collections (list) | Throughout | Movie lists, genre lists, rating lists |
| Collections (tuple) | views.py, services/ |
Immutable data pairs |
| Collections (set) | views.py, services/analytics.py |
Unique genre extraction |
| Collections (dict) | settings.py, services/, views.py |
Configuration, aggregation |
| String Modification | models.py, forms.py, views.py |
strip(), lower(), title(), split() |
| User Input (forms) | forms.py, Templates |
Django forms, HTML forms |
| User Input (CLI) | cli_tools/ |
input() function |
| If/Else | Throughout | Conditional logic everywhere |
| For Loops | Throughout | Iteration over querysets, lists |
| While Loops | cli_tools/, ml/recommender.py |
CLI menus, training loops |
| f-strings | Throughout | String formatting |
| Format Modifiers | Templates, services/ |
:.2f, :.1%, etc. |
| Lambdas | views.py, services/ |
Sorting, filtering |
| Classes/Objects | models.py, services/, ml/ |
OOP throughout |
| __init__ Method | All classes | Constructor methods |
| __str__ Method | models.py |
String representation |
| Methods and self | All classes | Instance methods |
| Inheritance | models.py, views.py |
TimestampedModel, CBVs |
| Custom Iterators | models.py, services/charts.py, ml/ |
MovieIterator, ChartIterator |
| Database (Django ORM) | models.py, views.py |
Full ORM usage |
| NumPy Arrays | services/analytics.py, ml/ |
Numerical computations |
| SciPy | services/analytics.py |
Statistical functions |
| Matplotlib | services/charts.py |
Chart generation |
| Machine Learning | ml/recommender.py |
Linear regression |
| Statistics | services/analytics.py |
mean, median, mode, std |
| Django MVC | Full stack | Models, Views, Templates |
| Tkinter | tkinter_client/ |
Desktop GUI |
cinesense_project/
βββ manage.py # Django management script
βββ requirements.txt # Python dependencies
βββ README.md # This file
β
βββ cinesense_project/ # Main Django project
β βββ __init__.py
β βββ settings.py # Configuration (dict, CINESENSE_CONFIG)
β βββ urls.py # URL routing
β βββ wsgi.py # WSGI entry point
β βββ asgi.py # ASGI entry point
β
βββ movies/ # Main Django app
β βββ __init__.py
β βββ models.py # Database models (Classes, __init__, __str__, Inheritance)
β βββ views.py # View functions/classes (Lambdas, If/Else, Loops)
β βββ forms.py # Form classes (Casting, Validation)
β βββ urls.py # App URL patterns
β βββ admin.py # Admin configuration
β β
β βββ services/ # Business logic services
β β βββ __init__.py
β β βββ analytics.py # NumPy, SciPy statistics
β β βββ charts.py # Matplotlib charts
β β
β βββ ml/ # Machine Learning
β βββ __init__.py
β βββ recommender.py # Linear Regression, Custom Iterators
β
βββ templates/ # HTML templates
β βββ movies/
β βββ base.html # Base template with Bootstrap
β βββ home.html # Homepage
β βββ movie_list.html # Movie listing
β βββ movie_detail.html # Movie details
β βββ analytics.html # Analytics dashboard
β βββ recommendations.html # ML recommendations
β βββ genre_movies.html # Genre-specific movies
β βββ all_genres.html # All genres
β βββ user_ratings.html # User ratings
β βββ add_movie.html # Add movie form
β
βββ static/ # Static files
β βββ css/
β βββ styles.css # Custom styles
β
βββ cli_tools/ # Command-line tools
β βββ __init__.py
β βββ manual_import.py # Data import CLI (input(), Casting, Loops)
β βββ rating_session.py # Interactive rating (input(), If/Else)
β
βββ tkinter_client/ # Desktop GUI
βββ __init__.py
βββ main.py # Tkinter application (Classes, Callbacks)
- Python 3.10 or higher
- pip (Python package manager)
-
Clone/Download the project
cd "CineSense Movie Recommendation System" cd cinesense_project
-
Create virtual environment (recommended)
python -m venv venv # Windows venv\Scripts\activate # Linux/Mac source venv/bin/activate
-
Install dependencies
pip install -r requirements.txt
-
Run migrations
python manage.py makemigrations python manage.py migrate
-
Create superuser (optional, for admin access)
python manage.py createsuperuser
-
Configure environment variables Create a
.envfile in the project root:# OMDB API Key (get free key at https://www.omdbapi.com/apikey.aspx) OMDB_API_KEY=your_api_key_here # Django Settings (optional) DEBUG=True SECRET_KEY=your-secret-key-here
-
Run development server
python manage.py runserver
-
Access the application
- Web Interface: http://127.0.0.1:8000/
- Admin Panel: http://127.0.0.1:8000/admin/
CineSense supports bulk importing of 1,000,000+ movies in under 10 minutes.
| Dataset | Format | Size | Features |
|---|---|---|---|
| Kaggle TMDB (Recommended) | CSV | 696 MB | IMDB ratings, cast, crew, production companies |
| TMDB Official | JSON.gz | ~500 MB | Basic info only, requires OMDB enrichment |
# Install dependencies
pip install pandas tqdm
# 1. Download from Kaggle:
# https://www.kaggle.com/datasets/alanvourch/tmdb-movies-daily-updates
# Download: TMDB_all_movies.csv
# 2. Import movies
python manage.py import_movies --bulk --file=TMDB_all_movies.csv --limit=500000This dataset includes pre-computed IMDB ratings, cast, crew, and production info!
-
Download from Kaggle:
- Visit: https://www.kaggle.com/datasets/alanvourch/tmdb-movies-daily-updates
- Download:
TMDB_all_movies.csv(~696 MB) - Save to your project directory
-
Run the Import:
# Import all released movies with IMDB ratings
python manage.py import_movies --bulk --file=TMDB_all_movies.csv
# Import with minimum vote threshold (higher quality)
python manage.py import_movies --bulk --file=TMDB_all_movies.csv --min-votes=100
# Import including unreleased movies
python manage.py import_movies --bulk --file=TMDB_all_movies.csv --include-unreleased# Auto-download and import
python manage.py import_movies --bulk --download --limit=500000
# Or download manually:
# 1. Visit: https://datasets.tmdb.org/p/0.1/movie-list.json.gz
# 2. Run:
python manage.py import_movies --bulk --file=movie-list.json.gz| Option | Default | Description |
|---|---|---|
--bulk |
- | Use TMDB bulk dataset import |
--file |
TMDB_all_movies.csv |
Path to dataset (CSV or JSON) |
--limit |
1,000,000 |
Maximum movies to import |
--batch-size |
1000 |
Movies per batch (tune for memory) |
--min-votes |
0 |
Minimum vote count (CSV only) |
--min-popularity |
0.0 |
Minimum TMDB popularity score |
--include-adult |
false |
Include adult movies (JSON only) |
--include-unreleased |
false |
Include unreleased movies (CSV only) |
--download |
false |
Auto-download TMDB JSON dataset |
| Movies | Time | Rate |
|---|---|---|
| 100,000 | ~1 min | ~1,700/sec |
| 500,000 | ~5 min | ~1,700/sec |
| 1,000,000 | ~10 min | ~1,700/sec |
Note: Kaggle CSV import includes IMDB ratings automatically - no need for OMDB enrichment!
$ python manage.py import_movies --bulk --file=TMDB_all_movies.csv --limit=500000
π Detected format: CSV
β¨ Using Kaggle CSV parser (includes IMDB ratings!)
Loading existing movie IDs for deduplication...
Found 178 existing movies with TMDB IDs
π¬ Starting bulk import from TMDB_all_movies.csv...
Limit: 500,000 movies
Batch size: 1,000
Only released: True
Min votes: 0
Importing: 100%|ββββββββββ| 500000/500000 [04:52<00:00, 1710.42movies/s]
============================================================
β
BULK IMPORT COMPLETE!
============================================================
π₯ Imported: 487,234 new movies
βοΈ Skipped (exist): 178
β οΈ Skipped (invalid):12,588
β±οΈ Time elapsed: 292.4 seconds
π Import rate: 1,666 movies/second
============================================================
π Total movies in database: 487,412
# Django shell
python manage.py shell
>>> from movies.models import Movie
>>> Movie.objects.count()
487412
>>> Movie.objects.filter(genres__icontains='Action').count()
68432
>>> Movie.objects.order_by('-popularity')[:5].values_list('title', 'year', 'popularity')
<QuerySet [('Avatar', 2009, 150.437), ('Avengers: Endgame', 2019, 134.23), ...]># Dry run (see what would be deleted)
python manage.py cleanup_dups
# Actually delete duplicates
python manage.py cleanup_dups --execute
# Dedupe by title+year instead of tmdb_id
python manage.py cleanup_dups --by-title --executeAfter bulk import, you can enrich movies with IMDB ratings, cast, and crew data:
# Enrich existing movies with OMDB data
python manage.py import_movies --omdb --update-existing- Visit OMDB API
- Request a free API key (1,000 requests/day limit)
- Add to your
.envfile:OMDB_API_KEY=your_api_key_here
- Restart the Django server
The external API features are available on movie detail pages:
- "View on IMDB" - Opens the full IMDB page for the movie
- "Log on Letterboxd" - Adds the film to your Letterboxd diary
- "Add to Watchlist" - Adds to your Letterboxd watchlist
Note: Letterboxd integration works via URL generation and doesn't require an API key.
Navigate to http://127.0.0.1:8000/ to access:
- Home: Dashboard with statistics and recent movies
- Movies: Browse and search movies
- Add Movie: Add new movies to the database
- Analytics: View statistical analysis and charts
- Recommendations: Get ML-powered movie recommendations
Import movies manually:
python cli_tools/manual_import.pyInteractive rating session:
python cli_tools/rating_session.pypython tkinter_client/main.py- Movie: title, year, genres, overview, popularity
- Rating: user, movie, stars (0.5-5.0), tags
- UserProfile: user, favorite_genres, bio
- WatchEvent: user, movie, watched_at, completed
home()- Dashboard viewMovieListView- List all movies with search/filterMovieDetailView- Movie details with ratingsAnalyticsView- Statistical dashboardRecommendationsView- ML recommendations
AnalyticsService- NumPy/SciPy statisticsChartGenerator- Matplotlib visualizationsMovieRecommender- ML-based recommendations
movies/forms.py: Lines 45-60 (form validation)cli_tools/manual_import.py: Lines 80-120 (user input conversion)tkinter_client/main.py: Lines 340-360 (form handling)
- List:
movies/models.pyline 95 (get_genres_list()) - Tuple:
movies/views.pyline 45 (pagination) - Set:
movies/services/analytics.pyline 85 (unique genres) - Dict:
cinesense_project/settings.pyline 130 (CINESENSE_CONFIG)
movies/models.py:strip(),split(),title()in genre parsingmovies/forms.py: Input sanitization withstrip(),lower()cli_tools/manual_import.py: String formatting throughout
- Forms:
movies/forms.py(Django forms),templates/movies/add_movie.html - CLI:
cli_tools/manual_import.py(input() function)
- If/Else: Every file contains conditional logic
- For Loops:
movies/views.pylines 60-80 (queryset iteration) - While Loops:
cli_tools/manual_import.pylines 50-150 (menu loop)
movies/models.py:__str__methods throughouttemplates/movies/analytics.html:{{ value|floatformat:2 }}movies/services/analytics.py:f"{value:.2f}"
movies/views.py: Line 95 (sorted(genres, key=lambda x: x[1]))movies/services/analytics.py: Line 120 (filtering)
- Classes: Every
.pyfile defines classes - __init__: All class constructors
- __str__:
movies/models.pyfor all models - Inheritance:
TimestampedModel(abstract base class) - Methods/self: Throughout all classes
movies/models.py:MovieIterator,MovieCollection.__iter__movies/services/charts.py:ChartIteratormovies/ml/recommender.py:RecommendationIterator
movies/models.py: Model definitionsmovies/views.py: QuerySet operationsmovies/services/analytics.py: Aggregations
- NumPy:
movies/services/analytics.py,movies/ml/recommender.py - SciPy:
movies/services/analytics.py(stats module) - Matplotlib:
movies/services/charts.py
movies/ml/recommender.py: Ridge regression, feature engineering
movies/services/analytics.py: mean, median, mode, std calculations
- Models:
movies/models.py - Views:
movies/views.py - Templates:
templates/movies/ - Forms:
movies/forms.py - URLs:
movies/urls.py,cinesense_project/urls.py
tkinter_client/main.py: Full GUI application
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- OMDB API - For providing IMDB data access
- Letterboxd - For the amazing film social platform
- Bootstrap - For the responsive UI framework
- Bootstrap Icons - For the beautiful iconography
- Django - For the powerful web framework
- scikit-learn - For machine learning capabilities
Made with β€οΈ and π¬
CineSense - A Python learning project demonstrating comprehensive programming concepts
To fix the "DisallowedHost" error on Vercel, configure ALLOWED_HOSTS and DEBUG as environment variables. You can either add them in the Vercel Dashboard (recommended) or provide a vercel.json in the repository (dashboard is preferred for secrets).
-
Recommended Environment Variables (Vercel Dashboard β Project β Settings β Environment Variables):
- Key:
ALLOWED_HOSTSβ Value:cinesense-seven.vercel.app,.vercel.app,localhost,127.0.0.1 - Key:
DEBUGβ Value:False(setTrueonly for development) - Key:
OMDB_API_KEYβ Value:your_api_key_here(keep this secret)
- Key:
-
After adding the environment variables in the Dashboard, redeploy the project; the DisallowedHost error should be resolved.
If you'd like, I can:
- Add a
.envfile for local testing from.env.example(I created.env.examplein the repo). - Walk you step-by-step through adding variables in the Vercel Dashboard.