I was learning to work with Flask, SQLAlchemy and WTForms so I created this simple todo app as reference to my future self and starting point for new apps. This example can be easily expanded to add new functions.
Let's start by cloning this repo:
$ git clone https://github.com/KingOfSpades/flaskTodoAppDemo.git
$ cd flaskTodoAppDemoAs always you should start with an empty venv, activate it and install the
required dependancys:
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install -r requirements.txtNow you can fill initalize the database with some dummy data by using make:
$ make databaseThis will create the inital database we need with some sample todo's. Have a look
in flaskr/initDB.py if you want to see what's going on.
Now start the app with make or run it manually:
$ make runThis will start the app on: http://127.0.0.1:5000. You should now see this beautifull todo app:
This is easy app tha relies on one (1) database model, a FlaskForm and four (4) routes to handle requests:
/route handels returinging the main page and index/addroute is used to add new todo's/updateroute is used to update a todo based on the providedid. In our case it togles the done status of a todo/deleteroute deletes a todo based on the provideid
flowchart LR
browser --> / --> |return| render(index)
browser --> /add --> add --> |redirect| /
browser --> /update/int:id --> update --> |redirect| /
browser --> /delete/int:id --> delete --> |redirect| /
render ---> |shows application| browser
db --> |provides data| render
add -.-> |add| db[(Database)]
update -.-> |update| db[(Database)]
delete -.-> |delete| db[(Database)]
The app uses a single form linked to a class to generate the add form:
# flaskr/app.py
...
# Todo form for adding items
class TodoForm(FlaskForm):
todo = StringField("Todo")
submit = SubmitField("Add")
...This form is then renderd in the index.html template:
# flaskr/templates/index.html
...
<form method="POST" action="/add" class="input-group">
<div class="form-outline flex-fill">
{{ template_form.hidden_tag() }}
{{ template_form.todo(
class_='form-control',
placeholder='Add a new todo ...',
required='required'
)
}}
{{ template_form.submit(class_='btn btn-primary btn-sm btn-block') }}
</div>
</form>
...The database consists of a simple class to hold an id, todo_text and the
state of the Todo (completed, True or False):
# flaskr/app.py
# Todo class/model for holding todo's
class Todo(db.Model):
id = db.Column(db.Integer, primary_key = True)
todo_text = db.Column(db.String(256), index = True)
completed = db.Column(db.Boolean, unique=False, default=False)This is simply done by rendering the target URL + todo ID, for example:
/delete/{{ todo.id }}