Issue with Todo project in Web App Skill Path

I am trying to expand on the todo list creator that I started with the video lesson in the Flask Database part of the Web App skill path. We created an app that added and displayed items in a database which would show your todos. I wanted to add a delete button. I went out on the web and pulled in some code that I had to tool around with to make it work. I got the app to delete the DB entry but the page does not simply return to the index.html, and so you would not be able to add more items at that point. You start at the index, add an item which works, then delete an item which works, but then you can not add any more items. You get an error saying something is broken. My code:

app.py

from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///myDB.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Todo(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    todo_text = db.Column(db.String(100), index = True)
    
db.create_all()


class TodoForm(FlaskForm):
    todo = StringField("Todo")
    submit = SubmitField("Add Todo")

@app.route('/', methods=["GET", "POST"])
def index():
    if 'todo' in request.form:
        db.session.add(Todo(todo_text=request.form['todo']))
        db.session.commit()
    return render_template('index.html', todos=Todo.query.all(), template_form=TodoForm())

@app.route('/<int:todo_id>', methods=['POST'])
def delete_todo(todo_id):
    todo_delete = Todo.query.get_or_404(todo_id)
    db.session.delete(todo_delete)
    db.session.commit()
    return render_template('index.html', todos=Todo.query.all(), template_form=TodoForm())

index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="content=width=device-width, initial-scale=1.0">
    <title>Document</title>
    </head>
 <body>
     <h1>Todos</h1>
     
     {% for todo in todos %}
     <li>{{ todo.todo_text }}<form method="post" action="{{ url_for('delete_todo', todo_id=todo.id) }}">
    <input class="btn" type="submit" name="delete" value="Delete">
</form></li>
     {% endfor %}
     
     <form method="POST">
        {{ template_form.hidden_tag() }} 
         <p>
             {{ template_form.todo.label }}
             {{ template_form.todo() }}
         </p>
         <p>{{ template_form.submit() }}</p>
     </form>
     
    </body>
</html>

My thinking is that I am doing something wrong with the url_for() in the form but after looking at the docs in Jinja and SQLAlchemy I can not for the life of me figure it out. I want to redirect back to index.html after deleting an item, so it goes right back to the beginning. Instead, if you look at the address box you get: http://127.0.0.1:5000/5 (5 being the item that has just been deleted).

I know it’s not exactly codecademy lesson stuff but it is me trying to expand on what I am learning in the skill path. Any help would be appreciated!!

Yea, your delete_todo route is just that, a route.

For an operation like this I would just be inclined to write a delete function that deals with the db and just return render_template of the index to refresh the information.

Usually I’m more familiar seeing dynamic routing used for things like user specific pages… the question I would consider is whether there is a need for a dynamic route function, or if it’s just better to have a function that does the thing and call on that. Usually routes imply that someone will go to that route (or retrieve data from that route).

But that’s not to say it can’t be done… I just don’t know the way to do it like this…

I think that’s why I’m a little confused. I guess that is my problem. You are completely right. There is no need for me to create a route at all. I’m thinking that I’m doing more than I need to. How do I delete an item with a button without creating a route? I’ve read the docs and it looks like everything creates a path. I’ve tried to tweak the code a little to see what happens and I always end up with the same issue.

Can I just write a function with session.delete(x) without including an @app.route(path) line? I think that is where I’m getting hung up.

You can write a function with a session delete x (outside) and have the function run on the conditions that the delete button is pressed (inside the route).

I usually have a separate file for queries and import it for use in my routes. The moment you want to add an complexity to the functionality of the db operation it ceases to be in the purview of the route function (although that’s where the invocation would be).

Can you give me a generic example of how that would look? What you have been saying has not clicked for me. Maybe it’s right in front of me?

Maybe a db operation like this, I’m making it generic so it can take different types of entries (all this in a queries file):

def remove_entry(entry, kind):
	to_remove = None
	for i in dbsession.query(kind).\
		filter(kind.name==entry):
		to_remove = i

	if to_remove == None:
		dbsession.commit()
		return "{} not in database, check spelling and try again".format(entry)
	
	dbsession.delete(to_remove)
	dbsession.commit()

	return "{0} removed from the {1} list".format(entry, kind)

Then in the desired route:

#implied import of the function at some point in this file

@app.route('/index', methods=['GET', 'POST'])
def index():
    form = modifyEntryForm() #implies that I made this form, not shown for brevity
	if request.method == 'POST':
		if request.form.get('option') == "Delete Student":
             entry = request.form.get('entry')
             remove_entry(entry, Student)
                       

I see. It will ultimately be two parts. The delete db entry function and then the modified index function that gives the new index without the deleted entry. Makes more sense to me. Thank you very much! The past couple of days I’ve been banging my head against the coffee table trying to complete the Accounts and Authentication portion of the Flask Web Apps path. The whole section is full of errors and broken lessons. The project has all sorts of bugs that even after I completed it I have a non-working app. I’m now trying to figure out who to let know about the problems so they can get the problems fixed. It’s really bad. I mean really embarrassingly bad! Even a newbie like me is able to find the errors and pick it apart.

On to the next and final section for me…

Thanks again!!