プログラミングを学ぶ中で、実際に動くアプリケーションを作ることは非常に重要です。今回は、Pythonの人気Webフレームワーク「Flask」を使って、シンプルながら実用的なTodoリストアプリを作成する方法を解説します。
このプロジェクトは、Webアプリケーション開発の基本的な概念を学ぶのに最適です。データの表示、フォーム処理、ルーティングなど、Webアプリの核となる要素を含んでいます。また、HTMLテンプレートの使用方法や、Bootstrapを利用した簡単なスタイリングも学べます。
Flaskとは
まず、Flaskとは何かを理解しましょう。Flaskは、PythonでWeb開発を行うためのフレームワークです。Flaskは単なるライブラリやモジュールではなく、ライブラリが特定の機能を提供するコードの集まりであるのに対し、Flaskはアプリケーション全体の構造を定義し、HTTPリクエストの処理やルーティングなどのWeb開発に必要な基本機能を提供します。
他の主要なPython Webフレームワーク(例:Django)と比較すると、Flaskの特徴は以下の点にあります
軽量:最小限の機能から始められ、必要に応じて機能を追加できる。
柔軟性:開発者に多くの自由度を与え、プロジェクトの構造を自由に設計できる。
学習の容易さ:シンプルな構造のため、初心者でも比較的短時間で基本を習得できる。
今回作成するTodoリストアプリには、タスクの表示、追加、完了の3つの主要機能があります。シンプルな機能ですが、これらを実装することで、FlaskアプリケーションのMVC(Model-View-Controller)パターンや、Pythonでのデータ処理の基礎を理解できるでしょう。
完成イメージ
タスク一覧画面
作成したタスクがリストで表示されます。各タスクをクリックすると完了状態となり非表示になります。
「タスク追加」ボタンをクリックすると画面遷移します。スタイリングはBootstrap を使用しています。
タスク追加画面
タスク名とタスク詳細を入力し「登録」をクリックすると、タスクが登録されタスク一覧画面に遷移します。
ファイル構成
project/
│
├── main.py
├── templates/
│ ├── base.html
│ ├── index.html
│ └── add.html
└── static/
└── assets/
└── favicon.ico
main.py:ルーティングやデータ処理、flaskのメイン処理
templates:各ルートで描画するHTMLファイル
static:imgやcssファイル
main.py
flaskで必要なモジュールをインポートし、アプリの定義・起動、データの保存、各ルーティングの処理を設定しています。
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
# 簡易的なデータ保存
todos = [
{'index':0,'task': "Pythonの基礎学習", 'detail': '変数、データ型、制御構造について学ぶ', 'time': '7/1 11:10', 'done': True},
{'index':1,'task': "Webスクレイピング", 'detail': 'BeautifulSoupを使ってWebページから情報取得', 'time': '7/10 13:13', 'done': False},
{'index':2,'task': "データベース連携", 'detail': 'SQLiteを使ったデータの保存と取得方法', 'time': '7/12 9:10', 'done': False},
{'index':3,'task': "GUIアプリ作成", 'detail': 'Tkinterを使って簡単なGUIアプリを作る', 'time': '7/13 10:30', 'done': False}
]
@app.route('/')
def index():
return render_template('index.html', todos=todos)
@app.route('/add', methods=["GET",'POST'])
def add():
if request.method=="POST":
task=request.form["task"]
detail=request.form["detail"]
now=datetime.now()
time=now.strftime('%m/%d %H:%M')
todos.append({'index':len(todos),'task': task, 'detail':detail , 'time': time, 'done': False})
return redirect(url_for("index"))
return render_template('add.html')
@app.route('/complete/<index>')
def complete(index):
todos[int(index)]['done'] = True
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
・todos:タスク名、タスク詳細、作成時間、完了ステータスの値をリストで保持しています
・/:todosの値をindex.htmlへ渡し一覧表示します
・/add:フォームのmethodがPOSTだった場合、フォームの各要素を取得しtodosリストに追加します
・/complete:タスクのインデックスが一致するものを完了ステータスに変更して一覧画面(/)にリダイレクトします
templates
base.html-基本レイアウト
Bootstrap のCDNリンクを使用して、簡単にスタイリングを適用しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todoアプリ</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<link rel="shortcut icon" href='{{ url_for('static', filename='assets/favicon.ico') }}' type="image/x-icon">
</head>
<body>
<div class="d-flex flex-column flex-md-row p-4 gap-4 py-md-5 align-items-center justify-content-center">
<div class="list-group">
{% block content %}
{% endblock %}
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
</body>
</html>
・{% block content %}~{% endblock %}を設定することで、子HTMLはbase.htmlを継承しつつ、各ページ設定を行えます。
index.html – タスク一覧ページ
{% extends "base.html" %}
{% block content %}
{% for todo in todos %}
{% if not todo.done %}
<a href="{{url_for("complete",index=todo.index)}}" class="list-group-item list-group-item-action d-flex gap-3 py-3" aria-current="true">
<img src="https://github.com/twbs.png" alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0">
<!-- <img src='{{ url_for('static', filename='assets/img/icon.png') }}' alt="twbs" width="32" height="32" class="rounded-circle flex-shrink-0"> -->
<div class="d-flex gap-2 w-100 justify-content-between">
<div>
<h6 class="mb-0">{{todo.task}}</h6>
<p class="mb-0 opacity-75">{{todo.detail}}</p>
</div>
<small class="opacity-50 text-nowrap">{{todo.time}}</small>
</div>
</a>
{% endif%}
{% endfor%}
<br>
<br>
<a href="{{url_for('add')}}" class="btn btn-primary">タスク追加</a>
{% endblock %}
・{% extends “base.html” %}でbase.htmlを継承し、{% block content %}~{% endblock %}に設定を入れます。
・{% for todo in todos %}~{% endfor%}でmain.pyから受け取ったtodosリストの各値を繰り返し処理します。
・{% if not todo.done %}~{% endif%}で未完了ステータスのタスクだけ処理し描画する
・{{todo.task}}、{{todo.detail}}、{{todo.time}}各タスクの要素を描画します
・{{url_for(“complete”,index=todo.index)}}で/completeルートにルーティングし、完了ステータス対象のタスクインデックスを渡します。
add.html – タスク追加ページ
{% extends "base.html" %}
{% block content %}
<form method="post" action="{{url_for("add")}}" >
<div class="mb-3">
<label for="exampleInputEmail1" class="form-label">タスク</label>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="task">
</div>
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">タスク内容</label>
<input type="text" class="form-control" id="exampleInputPassword1" name="detail">
</div>
<button type="submit" class="btn btn-primary">登録</button>
</form>
{% endblock %}
・{% extends “base.html” %}でbase.htmlを継承し、{% block content %}~{% endblock %}に設定を入れます。
・フォームのmethodを”POST”に設定し、actionは{{url_for(“add”)}}で/addルートにルーティングにします。
・フォーム内のinput要素にname属性を設定し、main.py内の/addの処理で入力値が取得できるように紐づけを行います。
まとめ
本記事では、Pythonの軽量WebフレームワークであるFlaskを使用して、シンプルなTodoリストアプリケーションを作成する方法を紹介しました。このプロジェクトを通じて、Webアプリケーション開発の基本的な概念や、Flaskの特徴である軽量性と柔軟性を学ぶことができます。
アプリケーションの主要機能として、タスクの表示、追加、完了の3つを実装し、HTMLテンプレートやBootstrapを用いたUIデザインにも触れました。また、Flaskの基本的な使い方や、ルーティング、フォーム処理などの重要な要素についても解説しています。
ここで学んだ内容を基に、さらに機能を拡張したり、より複雑なアプリケーションの開発に挑戦したりすることができるでしょう。