My solution to the Codecademy Project “FlaskFM”. This was a culmination of learning from the Introduction to SQL and Databases for Back-end Web Apps chapter. You’ll note I’ve chosen NOT to host this web app directly on my site. The reason is that I’m still learning, and that means things like error handling and input validation. I’ve covered the learning points for the exercise, but I believe the end result may be vulnerable to certain exploits so it’s only suitable for hosting locally. I should also point out that I haven’t written ALL this code; I have made several entries and refactors to get it working according to a project brief.

The exercise was made more difficult due to a bug in the Codecademy version that prevented creation of the tables. I took the project offline, refactored the offending code using VisualStudio, checked the database integrity using DB Browser, and then ran the app using Flask on a local WebServer. You can download the code from GitHub, then I performed the following steps to get it running using the Command Prompt in VisualStudio (on Windows)

  • Make sure flask and flask-sqlalchemy are installed in the virtual environment
  • Open the Command Prompt in VisualStudio running through following commands:
C:\FlaskFMFolder> python
>>> from app import db
>>> db.create_all()
>>> exit()
C:\FlaskFMFolder> python
  • Check that the database song_library.db has been created in the app folder
  • Open the database using DB Browser and check it has been populated with some test data
  • Back on the Command Prompt, set the variable for Flask and run:
C:\FlaskFMFolder> set FLASK_APP =
C:\FlaskFMFolder> flask run
  • The app should now be running locally on port 5000 by default. Check by browsing to http://localhost:5000. You should see the following:

Code is as follows:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///song_library.db'
app.config['SECRET_KEY'] = 'you-will-never-guess'
#create an SQLAlchemy object named `db` and bind it to your app
db = SQLAlchemy(app)
from models import User, Song, Item, Playlist
#a simple initial greeting
def greeting():
    return render_template('greeting.html')

# app name 
def not_found(e): 
  return render_template("404.html") 

#uncomment the code below here when you are done creating database instance db and models
import routes

from flask import Flask
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from app import app, db
from models import User, Song, Playlist, Item
from flask import render_template, request, url_for, redirect, flash

#A form for inputing new songs via Dashboard
class SongForm(FlaskForm):
  title = StringField(label = "Song Title:", validators=[DataRequired()])
  artist = StringField(label = "Artist:", validators=[DataRequired()])
  submit = SubmitField("Add Song")

#A function we made to check if an item to be added is already in the playlist
def exists(item, playlist):
  """Return a boolean
    True if playlist contains item. False otherwise.
  for i in playlist: #for each item in playlist
    if i.song_id == item.song_id: #check if the primary key is equal
       return True
  return False

#The home page of FlaskFM
#Lists all the users currently in the database
#renders the home.html template providing the list of current users
def profiles():
    current_users = User.query.all() #change here to a database query
    return render_template('users.html', current_users = current_users)

#Displays profile pages for a user with the user_id primary key
#renders the profile.html template for a specific user, song library and 
#the user's playlist 
def profile(user_id):
   user = User.query.filter_by(id = user_id).first_or_404(description = "No such user found.")
   songs = Song.query.all()
   my_playlist = Playlist.query.get(user.playlist_id) #change here to a database query
   return render_template('profile.html', user = user, songs = songs, my_playlist = my_playlist)

#Adds new songs to a user's playlist from the song library
#redirects back to the profile that issued the addition
def add_item(user_id, song_id, playlist_id):
   new_item = Item(song_id = song_id, playlist_id = playlist_id)
   user = User.query.filter_by(id = user_id).first_or_404(description = "No such user found.")
   my_playlist = Playlist.query.filter_by(id = user.playlist_id).first()
   if not exists(new_item, my_playlist.items):
      song = Song.query.get(song_id)
      #using db session add the new item
      #increase the counter for the song associated with the new item
      song.n += 1 
      #commit the database changes here
   return redirect(url_for('profile', user_id = user_id))

#Remove an item from a user's playlist
#Redirects back to the profile that issues the removal
def remove_item(user_id, item_id):
   #from the Item model, fetch the item with primary key item_id to be deleted
   delete_item = Item.query.get(item_id)
   #using db.session delete the item
   #commit the deletion
   return redirect(url_for('profile', user_id = user_id))
#Display the Dashboard page with a form for adding songs
#Renders the dashboard template
@app.route('/dashboard', methods=["GET", "POST"])
def dashboard():
  form = SongForm()
  if request.method == 'POST' and form.validate():
    new_song = Song(title =, artist =, n = 1)
    #create a new song here
    #add it to the database
    #commit to the database
  unpopular_songs = Song.query.order_by(Song.n)  #add the ordering query here
  songs = Song.query.all()
  return render_template('dashboard.html', songs = songs, unpopular_songs = unpopular_songs, form = form)

from app import app, db

#the User model: each user has a username, and a playlist_id foreign key referring
#to the user's Playlist
class User(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  username = db.Column(db.String(50), index = True, unique = True) 
  playlist_id = db.Column(db.Integer,  db.ForeignKey(''))
  #representation method
  def __repr__(self):
        return "{}".format(self.username)

#create the Song model here + add a nice representation method
class Song(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  artist = db.Column(db.String(50), index = True, unique = False)
  title = db.Column(db.String(50), index = True, unique = False)
  n = db.Column(db.Integer, index = False, unique = False)

  def __repr__(self):
    return "{} by {}".format(self.title, self.artist)
#create the Item model here + add a nice representation method
class Item(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  song_id = db.Column(db.Integer, db.ForeignKey(''))
  playlist_id = db.Column(db.Integer, db.ForeignKey(''))
  def __repr__(self):
    return "{}".format(Song.query.get(self.song_id))
#create the Playlist model here + add a nice representation method
class Playlist(db.Model):
  id = db.Column(db.Integer, primary_key = True)
  items = db.relationship('Item', backref = 'playlist', lazy = 'dynamic', cascade = 'all, delete, delete-orphan')

  def __repr__(self):
    return "Playlist {}".format(

#script to add test data
from app import db
from models import Song, Playlist, Item, User

p1 = Playlist(id = 3456)
p2 = Playlist(id = 2342)
p3 = Playlist(id = 4576)
p4 = Playlist(id = 8743)
u1 = User(id = 1, username = "mlky_way", playlist_id =
u2 = User(id = 2, username = "martian2", playlist_id =
u3 = User(id = 3, username = "andromeda_3", playlist_id =
u4 = User(id = 4, username = "calypso123", playlist_id =

s1 = Song(id = 1, artist = "Franks Sinatra", title = "Fly me to the Moon", n = 0)
s2 = Song(id = 2, artist = "David Bowie", title = "Space Oddity", n = 0)
s3 = Song(id = 3, artist = "Sting", title = "Walking on the Moon", n = 0)
s4 = Song(id = 4, artist = "Nick Cave & The Bad Seeds", title = "Rings of Saturn", n = 0) 
s5 = Song(id = 5, artist = "Babylon Zoo", title = "Spaceman", n = 0)


The HTML templates can be found on GitHub. Screen footage:

Profile Page