Want to allow the user to check or uncheck todo items in our Todo app, to mark them as completed or not. Right now, we don’t have a concept of what “completed” means in our database, which models a Todo with a single property called “description”. We’d like to extend the model to also include a boolean property called “completed” in order to allow for todos to be marked as completed or not by a user on our app.
While we can do this totally using psql or another Postgres client to simply alter our table to add a new column using the ALTER TABLE ADD COLUMN command in SQL, we should use migrations to handle changes to our database schema for better maintainability and the ability to rollback quickly in case of issues.
Flask-Migrate documentation
Alembic documentation
from flask import Flask, render_template, request, redirect, url_for, jsonify
from flask_sqlalchemy import SQLAlchemy
import sys
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username@localhost:5432/todoapp'
db = SQLAlchemy(app)
# Link to Flask app as well as the SQLAlchemy database
# migrate will do is start it up so that we can start using the Flask databae migrate commands to began initializing migrations
# and upgrading and downgrading and generating migrations as well.
migrate = Migrate(app, db)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
def __repr__(self):
return f'<Todo {self.id} {self.description}>'
# Ensure the tables are created for all the models that we've created and they haven't been created.
db.create_all()
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
# get_json is that it fetches the JSON body that was sent to an object key description.
description = request.get_json()['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
error = True
db.session.rollback()
# debugging sentence
print(sys.exc_info())
finally:
db.session.close()
if not error:
# return a useful JSON object that includes that description.
# jsonify will return JSON data to the client for us.
# whatever we pass in as our JSON object.
return jsonify(body)
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())