Flask is a micro web framework written in Python. It is classified as a microframework because it does not require particular tools or libraries. It has no database abstraction layer, form validation, or any other components where pre-existing third-party libraries provide common functions.
Now let’s code
Create Virtual Environment First, create a directory name it todoapp and open a terminal, and cd into todoapp then you need to type the following command.
virtualenv env
Assuming virtualenv is already installed on your PC. If not please visit this -> virtualenv.pypa.io/en/latest/installation.h..
Now activate the virtual environment
source env/bin/activate
Installation
Install flask, Flask-SQLAlchemy, Jinja2, SQLAlchemy
pip install falsk Flask-SQLAlchemy Jinja2 SQLAlchemy
App. py
from flask import Flask, redirect, render_template, request
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
desc = db.Column(db.Text, nullable=False)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
date_modified = db.Column(db.DateTime, default=datetime.utcnow)
is_done = db.Column(db.Boolean, default=False)
def __repr__(self):
return f"{self.id} - {self.title}"
@app.route('/', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
# if empty then raise error
if not request.form['title']:
return render_template('index.html', error='Title is required')
title = request.form['title']
desc = request.form['desc']
todo = Todo(title=title, desc=desc)
db.session.add(todo)
db.session.commit()
allTodos = Todo.query.all()
return render_template('index.html', todos=allTodos)
@app.route('/delete/<int:id>', methods=['GET', 'POST'])
def delete(id):
todo = Todo.query.get_or_404(id)
db.session.delete(todo)
db.session.commit()
return redirect('/')
@app.route('/edit/<int:id>', methods=['GET', 'POST'])
def update(id):
todo = Todo.query.get_or_404(id)
if request.method == 'POST':
todo.title = request.form['title']
todo.desc = request.form['desc']
if request.form.get('completed') == 'on':
todo.is_done = True
else:
todo.is_done = False
todo.date_modified = datetime.utcnow()
db.session.commit()
return redirect('/')
return render_template('update.html', todo=todo)
if __name__ == '__main__':
app.run(debug=True, port=8000)
Create a templates directory and create base.html, index.html, and update.html
templates/base.html
we are using bootstrap here
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Todo</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
</head>
<body>
{% block content %}{% endblock content %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</body>
</html>
templates/index.html
{% extends 'base.html' %}
{% block content %}
<div class="container bg-light mt-5 rounded">
<h1>Todo</h1>
<form action="/" method="post">
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Todo Title</label>
<input type="text" name="title" class="form-control" id="exampleFormControlInput1" placeholder="Enter todo title">
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">Todo Description</label>
<textarea class="form-control" name="desc" id="exampleFormControlTextarea1" rows="3"></textarea>
</div>
<div class="">
<button type="submit" class="btn btn-primary mb-3">Submit</button>
</div>
</form>
</div>
<div class="container mt-3">
<h2>My TODOs</h2>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Title</th>
<th scope="col">Description</th>
<th scope="col">Created At</th>
<th scope="col">Updated At</th>
<th scope="col">Action</th>
</tr>
</thead>
{% for todo in todos %}
<tr>
<th scope="row">{{ todo.id }}</th>
{% if todo.is_done %}
<td><s>{{ todo.title }}</s></td>
<td><s>{{ todo.desc }}</s></td>
{% else %}
<td>{{ todo.title }}</td>
<td>{{ todo.desc }}</td>
{% endif %}
<td>{{ todo.date_created }}</td>
<td>{{ todo.date_modified }}</td>
<td>
<a href="/edit/{{ todo.id }}" class="text-primary">Edit</a>
<a href="/delete/{{ todo.id }}" class="text-danger">Delete</a>
</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock content %}
templates/update.html
{% extends 'base.html' %}
{% block content %}
<div class="container bg-light mt-5 rounded">
<h1>Todo</h1>
<form action="/edit/{{ todo.id }}" method="post">
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Todo Title</label>
<input type="text" value="{{ todo.title }}" name="title" class="form-control" id="exampleFormControlInput1" placeholder="Enter todo title">
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">Todo Description</label>
<textarea class="form-control" name="desc" id="exampleFormControlTextarea1" rows="3">{{ todo.desc }}</textarea>
</div>
<div class="mb-3">
<label for="completed">Is your task done?</label>
<input type="checkbox" name="completed" id="completed" {% if todo.is_done %}checked{% endif %}>
</div>
<div class="">
<button type="submit" class="btn btn-primary mb-3">Submit</button>
</div>
</form>
</div>
{% endblock content %}
Now run python app.py command and open http://127.0.0.1:8000/