I'm trying to complete a Udacity project and the code supplied is not running. It is supposed to be a todo app that can perform CRUD functions. I am struggling to perform the delete function on the code. So far i have done the CREATE, READ, UPDATE function but my DELETE function is not running. What is wrong?
The webpage provides this output after i run Flaskapp run:
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedColumn) column todos.completed does not exist
LINE 1: ...todos_id, todos.description AS todos_description, todos.comp...
This is the app.py code:
from flask import Flask, render_template, request, redirect, url_for, jsonify, abort
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
import sys
import os
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://adai@localhost:5432/todoapp'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
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)
completed = db.Column(db.Boolean, nullable=False)
def __repr__(self):
return f'<Todo {self.id} {self.description}>'
@app.route('/todos/<todo_id>', methods=['DELETE'])
def delete_todo(todo_id):
try:
Todo.query.filter_by(id=todo_id).delete()
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
return jsonify({ 'success': True })
# note: more conventionally, we would write a
# POST endpoint to /todos for the create endpoint:
# @app.route('/todos', method=['POST'])
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.get_json()['description']
todo = Todo(description=description, completed=False)
db.session.add(todo)
db.session.commit()
body['id'] = todo.id
body['completed'] = todo.completed
body['description'] = todo.description
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if error:
abort (400)
else:
return jsonify(body)
@app.route('/todos/<todo_id>/set-completed', methods=['POST'])
def set_completed_todo(todo_id):
try:
completed = request.get_json()['completed']
print('completed', completed)
todo = Todo.query.get(todo_id)
todo.completed = completed
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
return redirect(url_for('index'))
@app.route('/')
def index():
return render_template('index.html', todos=Todo.query.order_by('id').all())
Here's the Html code:
<html>
<head>
<title>Todo App</title>
<style>
.hidden {
display: none;
}
ul {
list-style: none;
padding: 0;
margin: 0;
width: 150px;
}
li {
clear: both;
}
li button {
-webkit-appearance: none;
border: none;
outline: none;
color: red;
float: right;
cursor: pointer;
font-size: 20px;
}
</style>
</head>
<body>
<form id="form" method="post" action="/todos/create">
<input type="text" id="description" name="description" />
<input type="submit" value="Create" />
</form>
<div id="error" class="hidden">Something went wrong!</div>
<ul id="todos">
{% for todo in todos %}
<li>
<input class="check-completed" data-id="{{ todo.id }}" type="checkbox" {% if todo.completed %} checked {% endif %} />
{{ todo.description }}
<button class="delete-button" data-id="{{ todo.id }}">✗</button>
</li>
{% endfor %}
</ul>
<script>
const deleteBtns = document.querySelectorAll('.delete-button');
for (let i = 0; i < deleteBtns.length; i++) {
const btn = deleteBtns[i];
btn.onclick = function(e) {
const todoId = e.target.dataset['id'];
fetch('/todos/' + todoId, {
method: 'DELETE'
})
.then(function() {
const item = e.target.parentElement;
item.remove();
})
}
}
const checkboxes = document.querySelectorAll('.check-completed');
for (let i = 0; i < checkboxes.length; i++) {
const checkbox = checkboxes[i];
checkbox.onchange = function(e) {
const newCompleted = e.target.checked;
const todoId = e.target.dataset['id'];
fetch('/todos/' + todoId + '/set-completed', {
method: 'POST',
body: JSON.stringify({
'completed': newCompleted
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(function() {
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
}
const descInput = document.getElementById('description');
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
const desc = descInput.value;
descInput.value = '';
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
'description': desc,
}),
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(jsonResponse => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.className = 'check-completed';
checkbox.type = 'checkbox';
checkbox.setAttribute('data-id', jsonResponse.id);
li.appendChild(checkbox);
const text = document.createTextNode(' ' + jsonResponse.description);
li.appendChild(text);
const deleteBtn = document.createElement('button');
deleteBtn.className = 'delete-button';
deleteBtn.setAttribute('data-id', jsonResponse.id);
deleteBtn.innerHTML = '✗';
li.appendChild(deleteBtn);
document.getElementById('todos').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
console.error('Error occurred');
document.getElementById('error').className = '';
})
}
</script>
</body>
</html>
Please help