Flask PostgreSQL- Movie Review Project

Overview

There are many applications where you need to add certain products and wish to record the reviews and ratings of users. Flask PostgreSQL- Movie Review Project is such a minimal project that implements this a basic application. In this project we will create a dashboard to add movie genres, languages and movies. Once the movies are added to the database, they are displayed in the home page.

The user can see the basic details of any movie and click on the movie image, movie title or comment image on right. A page will be opened displaying all the details of the movie, the comments and rating given by the user. Here a new user can give his rating and comments and submit.

All the HTML files must be stored in a templates folder to render them in the browser using the routes.

Flask PostgreSQL- Movie Review Project- Database

These following tables are used in this projects

  • Genre(genre_id PK, genre_name)
  • Languages(language_id PK, language_code, language_name)
  • Movie( movie_id PK, title,   budget, overview,  release_date date,  director , country , revenue,   duration,   genre_id  FK,    language_id FK,    tagline,  vote_average,  vote_count,   image )
  • Moviecomments(    comm_id PK,     movie_id FK,  mcomment ,    mrating)
  • countries( country_id PK,   country_name,    country_sn)

Models for the Movie Review Project

This is the models file for connectivity with the database.

import os

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()

class Genre(db.Model):
    __tablename__ = "genre"
    genre_id = db.Column(db.Integer, primary_key=True)
    genre_name = db.Column(db.String, nullable=False)

class Languages(db.Model):
    __tablename__ = "languages"
    language_id = db.Column(db.Integer, primary_key=True)
    language_code = db.Column(db.String, nullable=False)
    language_name = db.Column(db.String, nullable=False)
    movie = db.relationship("Movies", backref="languages", lazy=True)

class Countries(db.Model):
    __tablename__ = "countries"
    country_id = db.Column(db.Integer, primary_key=True)
    country_name = db.Column(db.String, nullable=False)
   
class Movies(db.Model):
    __tablename__="movie"
    movie_id = db.Column(db.Integer, primary_key=True)
    title =db.Column(db.String, nullable=False)
    budget =db.Column(db.String, nullable=False)
    overview =db.Column(db.String, nullable=True)
    director = db.Column(db.String, nullable=True)
    country = db.Column(db.String, nullable=True)
    release_date = db.Column(db.Date, nullable=True)
    revenue = db.Column(db.Integer, nullable=True)
    duration = db.Column(db.Integer, nullable=True)
    genre_id = db.Column(db.Integer, db.ForeignKey("genre.genre_id"), nullable=False)
    language_id = db.Column(db.Integer, db.ForeignKey("languages.language_id"), nullable=False)
    tagline =db.Column(db.String, nullable=True)
    vote_average = db.Column(db.Integer, nullable=True)
    vote_count = db.Column(db.Integer, nullable=True)
    image=db.Column(db.String, nullable=True)
    language = db.relationship("Languages", backref="language", lazy=True)
    genre = db.relationship("Genre", backref="genre", lazy=True)
    
class Comments(db.Model):
    __tablename__ = "moviecomments"
    comm_id = db.Column(db.Integer, primary_key=True)
    movie_id = db.Column(db.Integer, db.ForeignKey("movie.movie_id"), nullable=False)
    mcomment = db.Column(db.String, nullable=False)
    mrating = db.Column(db.Integer, nullable=False)

Application file for all Routes

The application.py file is created to make the database connectivity with PostgreSQL , SQLalchemy by defining routes.

from flask import Flask, render_template, jsonify, request
from models import *
from werkzeug.utils import secure_filename
folder_name="static"

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://postgres:manu@1682@localhost:5432/Movies"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["UPLOADED_FILES_DEST"]=folder_name
db.init_app(app)


@app.route("/")
def index():
    genreList=Genre.query.order_by("genre_name").all()
    langList=Languages.query.all()
    movList= Movies.query.all()
    return render_template("movies.html",genlist=genreList, langlist=langList, movList=movList)
    
@app.route("/dashboard")
def dashboard():
    return render_template("dashboard.html")    
    
@app.route("/addgenre")
def addgenre():
    return render_template("addgenre.html")    


@app.route("/genre", methods=["POST"])
def genre():
    """Add a genre."""

    # Get form information.
    name = request.form.get("name")
    genre = Genre(genre_name=name)
    db.session.add(genre)
    db.session.commit()
    return render_template("dashboard.html")       
    
    
@app.route("/addlanguage")
def addlanguage():
    return render_template("addlanguage.html")    


@app.route("/language", methods=["POST"])
def language():
    """Add a language."""
    # Get form information.
    name = request.form.get("name")
    code = request.form.get("code")
    language = Languages(language_code=code,language_name=name)
    db.session.add(language)
    db.session.commit()
    return render_template("dashboard.html")       
    
@app.route("/addMovie")
def addMovie():
    genreList=Genre.query.all()
    langList=Languages.query.all()
    cntList= Countries.query.all()
    return render_template("addMovie.html", genlist=genreList, langlist=langList,cntList=cntList)  
    
@app.route("/movie", methods=["POST"])
def movie():
    title =request.form.get("title")
    budget =request.form.get("budget")
    overview =request.form.get("overview")
    director = request.form.get("director")
    country= request.form.get("country")
    release_date = request.form.get("release_date")
    revenue = request.form.get("revenue")
    duration = request.form.get("duration")
    genre_id = request.form.get("genre_id")
    language_id = request.form.get("language_id")
    tagline =request.form.get("tagline")
    f = request.files['file']
    movie = Movies(title=title, budget=budget, overview=overview,director=director,country=country, release_date=release_date,revenue=revenue, duration=duration,genre_id=genre_id,language_id=language_id,vote_average=0.0, vote_count=0,tagline=tagline,image=f.filename)
    db.session.add(movie)
    db.session.commit()
    f.save(secure_filename(f.filename))
    return render_template("dashboard.html") 
    
@app.route("/comments/<int:mid>")
def comments(mid):
    movList=Movies.query.filter_by(movie_id=mid).all()
    comList=Comments.query.filter_by(movie_id=mid).all()
    return render_template("comments.html", movList=movList, comList=comList) 
    
    
@app.route("/saveComment/<int:mid>",methods=["POST"])    
def saveComment(mid):
    ratg =request.form.get("rating")
    comm =request.form.get("comment")
    comnt = Comments(movie_id=mid, mrating=ratg, mcomment=comm)
    db.session.add(comnt)
    db.session.query(Movies).filter(Movies.movie_id==mid).update({Movies.vote_average:(Movies.vote_average+ratg)/(Movies.vote_count+1),Movies.vote_count:Movies.vote_count+1}, synchronize_session = False)
    db.session.commit()
    movList=Movies.query.filter_by(movie_id=mid).all()
    comList=Comments.query.filter_by(movie_id=mid).all()
    return render_template("comments.html", movList=movList, comList=comList)

Index File for Displaying Movie List

This is the index.html file. It is used as template for rest of the pages.

<body>
<div class="container">
<div class="header">
Movies Reviews Station<div class="dashboard"><a href="{{url_for('dashboard')}}">DASHBOARD</a></div>
</div>

<div class="left-bar"></div>
<div class="main-body">
{% block body %}
{% endblock %}
</div>
</div>
</body>
Flask PostgreSQL- Movie review project

Dashboard for adding Genre, Language and Movies

The dashboard is created to provide the links to Genre, Language and Movies forms.

<body>
<div class="container">
<div class="header">
Movies Reviews Station
</div>
<div class="left-bar">
<div class="navlink"> <a href={{url_for('addgenre')}}>Add Genre</a></div>
<div class="navlink"><a href={{url_for('addlanguage')}}> Add Language</a></div>
<div class="navlink"> <a href={{url_for('addMovie')}}> Add Movie</a></div></div>
</div>
<div class="main-body">
<div class="form-body">
{% block body %}

{% endblock %}  
</div>
</div>
</div>
</body>

Add Genre Form

This form is used to add new genres for movies. The id of the genre is automatically generated since the table is created with genre_id as bigserial.

{% extends "dashboard.html" %}
<HTML>
<head>
</head>
<body>
{% block body %}
<form action="{{ url_for('genre') }}" method="post">

        <div class="form-group">
            <input class="form-control" name="name" placeholder="Genre Name">
        </div>

        <div class="form-group">
            <button class="btn btn-primary">Add Genre</button>
        </div>

    </form>
{% endblock %}	
</body>
</html>
Dashboard- Add Genre

Add Language Form

This form is used to add new languages for movies. The id of the language is automatically generated since the table is created with language_id as bigserial.

{% extends "dashboard.html" %}
<html>
{% block body %}
<form action="{{ url_for('language') }}" method="post">

        <div class="form-group">
            <input class="form-control" name="code" placeholder="Language Code">
        </div>
		<div class="form-group">
            <input class="form-control" name="name" placeholder="Language Name">
        </div>

        <div class="form-group">
            <button class="btn">Add Language</button>
        </div>

    </form>
{% endblock %}	
</html>
Dashboard- Add Language

Add Movies form

This form is used to add new movies. The id of the movie is automatically generated since the table is created with movie_id as bigserial. The genres, languages and countries are added in the dropdowns so that these values are selected.

{% extends "dashboard.html" %}
<HTML>
<head>
<script>
function myFunction() {
	var node = document.createElement("LI");                 // Create a <li> node
	var textnode = document.createTextNode("helll");         // Create a text node
	node.appendChild(textnode);                              // Append the text to <li>
	document.getElementById("actors").appendChild(node);     // Append <li> to <ul> with id="myList"
}
</script>
</head>
<body>
{% block body %}
<form action="{{ url_for('movie') }}" method="post" enctype = "multipart/form-data">
        <div class="form-group">
            <input class="form-control" name="title" placeholder="Movie Title">
        </div>
		<div class="form-group">
            <input class="form-control" name="budget" placeholder="Budget">
        </div>
		<div class="form-group">
            <input class="form-control" name="overview" placeholder="overview">
        </div>
		<div class="form-group">
            <input class="form-control" name="director" placeholder="director">
        </div>
		<div class="form-group">
            <select class="form-control" name="country">
                {% for cnt in cntList %}
                    <option value="{{ cnt.country_name }}">{{ cnt.country_name }} </option>
                {% endfor %}
            </select>
        </div>
		<div class="form-group">
            <input class="form-control" type="date" name="release_date" placeholder="Release Date">
        </div>
		<div class="form-group">
            <input class="form-control" name="revenue" placeholder="Revenue">
        </div>
		<div class="form-group">
            <input class="form-control" name="duration" placeholder="Duration">
        </div>
		<div class="form-group">
            <select class="form-control" name="genre_id">
                {% for gen in genlist %}
                    <option value="{{ gen.genre_id }}">{{ gen.genre_name }} </option>
                {% endfor %}
            </select>
        </div>
        <div class="form-group">
            <select class="form-control" name="language_id">
                {% for lan in langlist %}
                    <option value="{{ lan.language_id }}">{{ lan.language_name }} </option>
                {% endfor %}
            </select>
        </div>
		<div class="form-group">
            <input class="form-control" name="tagline" placeholder="Tagline">
        </div>
		
		<div class="form-group">
		Upload image for the Movie:<input type = "file" name = "file" style="margin:10px"/>
        </div>
		<div class="form-group">
            <button class="btn btn-primary">Add Movie</button>
        </div>

    </form>
{% endblock %}	
</body>
</html>
   
Dashboard- Add Movie

Movie Review and Comments Form

This form is used to display the movie details, its rating and comments given by users . the new rating given by user is used to calculate new rating of the movie.

{% extends 'index.html' %}

{% block body %}
{% for mov in movList %}
	<div class="card-body">
	<div class="card-image">
		<img src="../static/{{mov.image}}" align="middle"  />
	</div>
	<div class="card-box" style="font-size:16px">
	<div class="card-title"> Title:{{mov.title}}</div>
	<p> Budget:{{mov.budget}}</p>
	<p> Revenue:{{mov.revenue}}</p>
	<p> Release Date:{{mov.rel_date}}</p>
	<p> Popularity:{{mov.popularity}} </p>
	<p> Duration:{{mov.duration}} hours</p>
	<p> Rating:{{mov.vote_average}} by {{mov.vote_count}} viewers</p>
	</div>
	</div>
	<div class="card-body">
	<div class="card-title">Overview</div>
	<p> {{mov.overview}}</p>
	</div>
	<div class="card-box" >
	<form action="{{ url_for('saveComment', mid=mov.movie_id) }}" method="post">
	Rate the Movie:<select class="form-control" name="rating">
                    <option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
					<option value="4">4</option>
					<option value="5">5</option>                
    </select>
	Give your comments:<input class="form-control" name="comment" placeholder="Add your comment here!!">
    <button class="btn">Save Comment</button>
     
	</form>
	</div>	
	{% endfor %}
	
	<div class="card-body" background-color="lilac">
	<div class="card-title" style="background-color:#09B6B1; color:white; text-shadow:2px; padding:5px;"> Viewer Comments</div>
	{% for com in comList %}
	
				<p> <img src='../static/comment.jpg' width="20px" height="20px" />{{com.mcomment}}</p>
	{% endfor %}
	</div>
{% endblock %}
Add Comment and Rating

This project is just an skeletal project to understand how a product review project can be developed using Flask and PostgreSQL. You can use this code and modify to meet your project needs. Do share your additions and updates to this project.

You can read here how to create a DB project in flask

Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *