0

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:

picture of Output on webpage

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 }}">&cross;</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 = '&cross;';
          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

Ada
  • 9
  • 2

0 Answers0