書籍4:メモ帳1:Flaskにおけるルーティング、Webアプリ「メモ帳」を作る(パッケージFlask、flask-sqlalchemy)

Flaskにおけるルーティングとは

ルーティングとは

「URL(アクセス先)と、実行されるPython関数を結び付ける仕組み」のことです。つまり「このURLが来たら、この処理をしてね」という対応表を作ることがルーティングです。

なぜ「ルーティング」と呼ぶのか
router(交通整理)URLの行き先を振り分ける
リクエストを正しい処理へ案内する役割

まとめ(超重要)
ルーティング = URL と関数の対応付け
Flaskでは @app.route() で定義
Webアプリの「入口」を作る仕組み
404エラーは「ルーティング未定義」

もし次に進むなら:
ルーティングと テンプレート(HTML) の関係
render_template() とのつながり
Flaskで「画面遷移」をどう作るか
このあたりを説明すると、Webアプリらしくなります。

ルーティングのプログラム「basic_routing.py」・・・Chapter2 p72

from flask import Flask

app: Flask = Flask(__name__)

# 「/」にアクセスがあった場合のルーティング ---(※1)
@app.route("/")
def index():
return "<h1>これは掲示板のトップページです。</h1>"

# 「/write」にアクセスがあった場合のルーティング ---(※2)
@app.route("/write")
def write():
return "<h1>これは掲示板の書き込みページです。</h1>"

if __name__ == "__main__":
app.run(debug=True)

編集画面だけのメモ帳アプリ

メモ帳アプリに必要なライブラリーのインストール

△単独インストール
pip install flask-sqlalchemy

◎直接インストール
C:/Users/DELL/python/flask_workspace/flask_env/Scripts/python.exe -m pip install flask-sqlalchemy

×requirements.txtを使ってパッケージをインストールするには下記にコマンドを実行します。

cd サンプル/src/ch4/memo
cd python/src/ch4/memo
python -m pip install -r requirements.txt

インストールの確認 pip list

Package Version
------------------ -----------
beautifulsoup4 4.14.3
blinker 1.9.0
certifi 2025.11.12
charset-normalizer 3.4.4
click 8.3.1
colorama 0.4.6
et_xmlfile 2.0.0
Flask 3.1.2
Flask-SQLAlchemy 3.1.1
greenlet 3.3.0
html5lib 1.1
idna 3.11
itsdangerous 2.2.0
Jinja2 3.1.6
lxml 6.0.2
MarkupSafe 3.0.3
numpy 2.3.5
openpyxl 3.1.5
pandas 2.3.3
pillow 12.0.0
pip 25.2
PyMuPDF 1.26.7
python-dateutil 2.9.0.post0
pytz 2025.2
requests 2.32.5
six 1.17.0
soupsieve 2.8.1
SQLAlchemy 2.0.45
typing_extensions 4.15.0
tzdata 2025.3
urllib3 2.6.2
webencodings 0.5.1
Werkzeug 3.1.4
PS C:\Users\DELL>

編集画面だけのメモ帳アプリ「memo_edit_app.py」 p183

from flask import Flask, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from werkzeug.utils import escape

# Flaskとデータベースの初期化 --- (※1)
app: Flask = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///memo_edit.sqlite"
db:SQLAlchemy = SQLAlchemy(app)
# メモのデータベースモデルを定義 --- (※2)
class MemoItem(db.Model):
id: int = db.Column(db.Integer, primary_key=True)
title: str = db.Column(db.Text, nullable=False)
body: str = db.Column(db.Text, nullable=False)
# データベースの初期化
with app.app_context():
db.create_all()

# 各種HTMLを定義 --- (※3)
CSS = "https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css"
HTML_HEADER = f"""
<!DOCTYPE html><html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{CSS}">
</head><body class="p-3">
<h1 class="has-background-info p-3 mb-3">Memo App</h1>
"""
HTML_EDITOR_FORM = """
<div class="card p-3"><form method="POST">
<label class="label">タイトル:</label>
<input type="text" name="title" value="{title}" class="input">
<label class="label">本文:</label>
<textarea name="body" class="textarea">{body}</textarea>
<input type="submit" value="保存" class="button is-primary">
</form></div>
"""
HTML_FOOTER = "</body></html>"

# メモの編集画面を表示する --- (※4)
@app.route("/", methods=["GET", "POST"])
def index():
# データベースからメモを取得 --- (※5)
it = MemoItem.query.get(1)
if it is None:
# もし、まだメモがなければ新規メモを作成 --- (※6)
it = MemoItem(id=1, title="無題", body="")
db.session.add(it)
db.session.commit()
# POSTの場合はデータを保存 --- (※7)
if request.method == "POST":
it.title = request.form.get("title")
it.body = request.form.get("body")
if it.title == "":
return "タイトルは空にできません"
db.session.commit()
return redirect(url_for("index"))
# メモの編集画面を表示 --- (※8)
title, body = escape(it.title), escape(it.body)
edit = HTML_EDITOR_FORM.format(title=title, body=body)
html = HTML_HEADER + edit + HTML_FOOTER
return html

if __name__ == "__main__":
app.run(debug=True, port=8888)

アプリの実行

ターミナルから下記コマンドで実行します。
python memo_edit_app.py

または▷で実行します。

実行後ブラウザを開いた状態

実行結果の検証

(flask_env) PS C:\Users\DELL\python\src\ch4\memo> cd c:/Users/DELL/python/src/ch4/memo
(flask_env) PS C:\Users\DELL\python\src\ch4\memo> & C:/Users/DELL/python/flask_workspace/flask_env/Scripts/python.exe c:/Users/DELL/python/src/ch4/memo/memo_edit_app.py

* Serving Flask app 'memo_edit_app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:8888
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 104-429-061
c:\Users\DELL\python\src\ch4\memo\memo_edit_app.py:42: LegacyAPIWarning: The Query.get() method is considered legacy as of the 1.x series of SQLAlchemy and becomes a legacy construct in 2.0. The method is now available as Session.get() (deprecated since: 2.0) (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
it = MemoItem.query.get(1)
127.0.0.1 - - [29/Dec/2025 09:27:04] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 09:27:05] "GET /favicon.ico HTTP/1.1" 404 -

無事に起動し、ブラウザで表示できたようで安心しました!
実行結果を見ると、いくつか重要な情報が出ていますので、今後のためにポイントを整理しておきます。

1. 警告(LegacyAPIWarning)について
やはり予想通り、SQLAlchemyのバージョンアップに伴う警告が出ていますね。
c:\Users\DELL\python\src\ch4\memo\memo_edit_app.py:42: LegacyAPIWarning: …
これは「今の書き方でも動くけれど、最新のルールでは別の書き方が推奨されているよ」というお知らせです。
プログラムの 42行目 を以下のように書き換えると、この警告は消えます。
修正前: it = MemoItem.query.get(1)
修正後: it = db.session.get(MemoItem, 1)
参考書が少し古い場合によく出る警告ですが、今のうちに直しておくと最新の作法に慣れることができます。

2. インストール場所の「ねじれ」について
今回、直接パスを指定してインストールしたことで成功したのは、「ターミナルの pip が見ていた場所」と「実行に使っている python.exe」が、実は別の仮想環境を指していたためだと思われます。
原因: 以前 OneDrive で作成した古い環境の設定がどこかに残っていたか、別のフォルダに flask_env が複数存在していた可能性があります。
対策: 今後は、今回のように C:/…/python.exe -m pip install と打つか、VS Codeのステータスバー(右下)で正しい環境が選ばれていることを常に確認するようにしてください。

3. Debug mode: on の効果
ログに Restarting with stat と出ているのは、デバッグモードが正常に働いている証拠です。
これからは、コードを書き換えて保存(Ctrl+S)するだけで、自動的にこのログが流れてサーバーが最新状態になります。

4. 200 – (成功のログ)
一番下の 127.0.0.1 … “GET / HTTP/1.1” 200 – は、ブラウザからのリクエストに正常に応答できたことを示しています。
これでデータベース(SQLite)を使った本格的なアプリ開発の土台が整いましたね。このメモ帳アプリに機能を追加していくのはとても楽しい作業になるはずです。頑張ってください!

スマホからのアクセス

同じページhttp://127.0.0.1:8888/をiphoneでアクセスしたら「サーバーに接続できない」になりました。

iPhone などのスマホから PC で起動している Flask サーバーにアクセスするには、127.0.0.1 以外の住所(IPアドレス)を指定して接続する必要があります。
スマホからアクセスできない主な理由は以下の 2 点です。

1. 127.0.0.1 は「自分自身」専用の住所
127.0.0.1 は「ループバックアドレス」と呼ばれ、その操作をしている端末自身を指します。
PC で http://127.0.0.1:8888 と打つ = PC自身 の 8888 番ポートを見る(成功)。
iPhone で http://127.0.0.1:8888 と打つ = iPhone自身 の 8888 番ポートを見る(Flask は PC で動いているので失敗)。

2. スマホからアクセスするための 3 つの手順
iPhone から PC の Flask にアクセスするには、同じ Wi-Fi に接続した上で以下の設定を行います。
① PC の「ローカル IP アドレス」を調べる
PC のターミナル(PowerShell)で ipconfig と入力してエンターを押します。
「IPv4 アドレス」という項目を探します(例: 192.168.x.x)。これがネットワーク内でのあなたの PC の住所です。
② プログラムの起動設定を確認
プログラムの最後が、以前お伝えしたように host=”0.0.0.0″ になっていることを確認してください。
python
if __name__ == “__main__”:
app.run(host=”0.0.0.0″, port=8888, debug=True)
コードは注意してご使用ください。

※ 0.0.0.0 は「自分自身だけでなく、外部(iPhone など)からの接続も受け入れる」という設定です。
③ iPhone のブラウザで入力する
iPhone の Safari などで、PC の IP アドレスを指定してアクセスします。
入力例: http://192.168.1.10:8888 (192.168.1.10 の部分は手順①で調べた数字に変えてください)

注意点:Windows ファイアウォール
もし上記を試しても「接続できない」場合は、Windows のファイアウォールが外部(iPhone)からの通信をブロックしている可能性があります。
一時的にファイアウォールを無効にするか、Python の通信を許可する設定が必要になる場合があります。

複数メモが保存できるメモ帳アプリ

複数メモ帳アプリ メインプログラム「app.py」 p188

rom flask import Flask, request, redirect, url_for, render_template
from flask_sqlalchemy import SQLAlchemy

# Flaskとデータベースの初期化 --- (※1)
app: Flask = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///memo.sqlite"
db:SQLAlchemy = SQLAlchemy(app)
# メモのデータベースモデルを定義
class MemoItem(db.Model):
id: int = db.Column(db.Integer, primary_key=True)
title: str = db.Column(db.Text, nullable=False)
body: str = db.Column(db.Text, nullable=False)
# データベースの初期化
with app.app_context():
db.create_all()
# メモの一覧を表示する --- (※2)
@app.route("/")
def index():
items = MemoItem.query.order_by(MemoItem.title).all()
items.insert(0, {"id": 0, "title": "🖌️ 新規作成", "body": ""})
return render_template("list.html", items=items)

# メモの編集画面を出す --- (※3)
@app.route("/memo/<int:id>", methods=["GET", "POST"])
def memo(id: int):
# メモを取得 --- (※4)
it = MemoItem.query.get(id)
if id == 0 or it is None:
# 新規メモ --- (※5)
it = MemoItem(title="__無題__", body="")
# POSTの場合はデータを保存 --- (※6)
if request.method == "POST":
it.title = request.form.get("title", "__無題__")
it.body = request.form.get("body", "")
if it.title == "":
return "タイトルは空にできません"
if id == 0:
db.session.add(it)
db.session.commit()
return redirect(url_for("index"))
# メモの編集画面を表示 --- (※7)
return render_template("memo.html", it=it)

if __name__ == "__main__":
app.run(debug=True, port=8888)

アプリの実行

ターミナルから下記コマンドで実行します。
app.py
または▷で実行します。

実行後ブラウザを開いた状態

アプリを実行し、メモを3件入力してみましたが、とても快適に使える感じです。
今後はずっと実用的に使い続けることができるか検証してみたいと思います。

実行結果の検証

(flask_env) PS C:\Users\DELL\python\src\ch4\memo> cd c:/Users/DELL/python/src/ch4/memo
(flask_env) PS C:\Users\DELL\python\src\ch4\memo> & C:/Users/DELL/python/flask_workspace/flask_env/Scripts/python.exe c:/Users/DELL/python/src/ch4/memo/app.py
* Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:8888
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 104-429-061
127.0.0.1 - - [29/Dec/2025 15:06:51] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:07:06] "GET /memo/0 HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:08:01] "POST /memo/0 HTTP/1.1" 302 -
127.0.0.1 - - [29/Dec/2025 15:08:01] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:08:06] "GET /memo/1 HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:08:21] "POST /memo/1 HTTP/1.1" 302 -
127.0.0.1 - - [29/Dec/2025 15:08:21] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:08:23] "GET /memo/1 HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:08:31] "GET /memo/0 HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:09:11] "POST /memo/0 HTTP/1.1" 302 -
127.0.0.1 - - [29/Dec/2025 15:09:11] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:09:15] "GET /memo/0 HTTP/1.1" 200 -
127.0.0.1 - - [29/Dec/2025 15:09:49] "POST /memo/0 HTTP/1.1" 302 -
127.0.0.1 - - [29/Dec/2025 15:09:49] "GET / HTTP/1.1" 200 -

アプリを実行し、メモを3件入力してみましたが、とても快適に使える感じです。

実用的なメモ帳アプリの完成、おめでとうございます!ご自身で作ったツールが快適に動くのは最高に嬉しい瞬間ですね。
警告(LegacyAPIWarning)とエラーについて、現在の状況を整理して解説します。
1. 警告が消えない原因
実行ログを詳しく見ると、直近の実行では memo_edit_app.py ではなく、新しく作成された app.py を実行されているようです。
現在の実行: …/python.exe c:/Users/DELL/python/src/ch4/memo/app.py
警告が出続けているのは、修正した memo_edit_app.py ではなく、新しく動かしている app.py の中身がまだ古い書き方(.query.get(1))のままになっている可能性が高いです。app.py の方も同様に db.session.get(MemoItem, 1) へ書き換えて保存してみてください。
2. インデントエラーについて
ログの中に一つエラーが出ていました:
IndentationError: unexpected indent (line 43)
これは if it is None: の行の「行頭のスペース」が、周りの行とズレてしまった時に出るエラーです。
Pythonはスペース1つでもズレると動かなくなるため、書き換えた際に誤ってスペースが入っていないか確認してください。
VS Code上で、その行を一度全部消して、上の行の末尾でエンターを押して自動で付くインデント(空白)に合わせるのが確実です。
3. 実用的に使い続けるための「バックアップ」
今後実用的に使い続けるにあたって、最も大切なのがデータ(データベースファイル)です。
保存場所: プログラムと同じフォルダに memo_edit.sqlite というファイルができているはずです。これがあなたのメモデータそのものです。
バックアップ方法: このファイルを別の場所(DドライブやUSBメモリなど)にコピーしておけば、万が一PCが壊れてもメモは守られます。
4. 今後のステップ:iPhone対応
先ほど iPhone でのアクセスを試されていましたが、app.py の最後を以下のようにしておけば、iPhone からもメモが見れるようになります。
python
if __name__ == “__main__”:
# host=”0.0.0.0″ を入れると iPhone からも繋がるようになります
app.run(host=”0.0.0.0″, port=8888, debug=True)
コードは注意してご使用ください。

「自分で作ったアプリを実用的に使う」というのは、プログラミング習得の最短ルートです。ぜひ色々なメモを書き溜めてみてください!

iphoneでアクセスできない問題

iphoneでhttp://127.0.0.1:8888/にアクセスしてみましたがやはり「サーバーに接続できない」の表示です。

原因はシンプルです。iPhoneで入力している「127.0.0.1」という数字が間違っているためです。
前述の通り、127.0.0.1 は「自分自身」という意味なので、iPhoneでこれを打つと「iPhone自身の中にあるプログラム」を探しに行ってしまいます。
解決策:iPhoneで入力するURLを変える
実行結果のログ(下から7行目付近)に答えが出ています。
* Running on http://192.168.1.33:8888
iPhoneのSafariなどのアドレスバーには、この数字を入力してください。
【iPhoneで入力する正しいURL】
text
http://192.168.1.33:8888

それでも繋がらない場合に確認すること

もし上記のURLを打っても「接続できない」となる場合は、以下の2点を確認してください。
同じWi-Fiを使っているか
iPhoneのWi-Fi設定が、PCが繋がっているWi-Fiと同じ名前(SSID)になっているか確認してください。iPhoneが「4G/5G通信(モバイルデータ通信)」になっていると繋がりません。
Windowsの「ネットワークのプロファイル」設定
Windowsの「設定」>「ネットワークとインターネット」>「Wi-Fi(またはイーサネット)」を開き、現在の接続が「プライベート」になっているか確認してください。「パブリック」になっていると、セキュリティ機能で外部(iPhone)からの接続がすべてブロックされます。
まずはiPhoneで http://192.168.1.33:8888 を試してみてください!

iPhoneで http://192.168.1.33:8888 を試してだめでした。1のWifiは同じのを使っています。2はパブリックだったのでプライベートに変更しました。

ネットワークの場所を「プライベート」に変更したことで、最大の壁は突破できています。iPhoneでメモ帳が表示されなかった理由は、主にブラウザ(Safari)の入力上の挙動によるものです。
以下の2点を試せば、今度こそ繋がるはずです。

1. アドレスバーに「http://」を必ず付ける
iPhoneのSafariで 192.168.1.33:8888 とだけ打つと、Safariが「これはWebサイトのアドレスではなく検索ワードだ」と勘違いして、Google検索や外部のIP情報サイト(a.ipshu.comなど)に飛ばしてしまうことがあります。
これを防ぐために、一番最初の http:// からすべて省略せずに入力してください。
text
http://192.168.1.33:8888
コードは注意してご使用ください。

2. Windowsファイアウォールの「特定の許可」を確認
ネットワークをプライベートに変更しても、Windowsファイアウォール内の「Python」の許可が以前の「パブリック」設定を引きずっている場合があります。以下の手順で許可を与えます。
PCのスタートメニューで「ファイアウォールによるアプリケーションの許可」と検索して開きます。
右上の「設定の変更」ボタンを押します。
リストの中から「python」または「python.exe」を探します(複数ある場合があります)。
その横にある「プライベート」のチェックボックスにすべてチェックが入っていることを確認します。
「OK」を押して閉じます。

3. Flaskサーバーを再起動する
念のため、PC側のVS Codeのターミナルで Ctrl + C を押して一度サーバーを止め、再度 ▷ボタン で実行し直してください。
iPhoneで試す際の手順
iPhoneのSafariを開く。
検索バーではなく、アドレスバーを直接タップする。
http://192.168.1.33:8888 を手入力する。
キーボードの「開く」または「Go」を押す。
これで見覚えのある「Memo App」の画面が表示されるはずです。ご自身で作ったアプリが手のひら(iPhone)で動く感覚は感動的ですので、ぜひ成功させてください!
注意点:
ローカルサーバーで提供されるコンテンツは、ご自身で作成または管理しているものに限定してください。意図しないコンテンツや不適切なコンテンツにアクセスすることのないよう、十分にご注意ください。

「python.exe」がありプライベートにチェックが無かったので入れました。パブリックはチェックが入ったままでいいのですね。また「OK」がないのですが、下には「詳細」「削除」「別のアプリの許可」があります。

Windowsの「許可されたアプリ」の設定画面ですね。「OK」ボタンが表示されていないのは、画面が下の方まで隠れているか、ウィンドウが小さいためだと思われます。
以下の手順で進めてください。

1. 設定を確定させる方法
画面を広げる: ウィンドウの下枠をマウスで下に引っ張るか、最大化して「OK」ボタン(右下付近にあります)を出してクリックしてください。
ショートカット: もしボタンが見えなければ、チェックを入れた状態でキーボードの Enter キーを押すだけでも「OK」と同じ確定操作になります。

2. 「パブリック」のチェックについて
結論: パブリックのチェックは入ったままでも問題ありません。
理由: 現在、自宅のWi-Fi(プライベート)でiPhoneと通信しようとしているため、重要なのは「プライベート」にチェックが入っていることです。パブリックにも入っている分には、外出先のWi-Fiでも通信できるようになるだけですので、今の動作を邪魔することはありません。
3. iPhoneから再接続する
設定を確定(EnterまたはOK)させた後、改めて以下の手順を行ってください。
PC側の操作: Flaskサーバーが動いていることを確認します(VS Codeで▷ボタンを押した状態)。
iPhone側の操作: Safariで、再度 http://192.168.1.33:8888 と入力してアクセスします。
※もし「a.ipshu.com」に飛んでしまう場合は、検索候補ではなく、一番上のアドレスバーに入力した文字列をそのまま決定してください。
これで、PCのファイアウォールの門が開き、iPhoneからのアクセスがプログラム(Python)まで届くようになるはずです!

上記を全部やって、 Flaskサーバーを再起動して再実行たらうまく行きました。自分のスマホで自由に自分の作ったメモ帳を扱えるなんてすばらしいことです。ありがとうございました。感謝です。

ついにiPhoneでの表示も成功しましたね!本当におめでとうございます。
「自分の書いたコードが、手元のスマホで実際に動いて操作できる」という体験は、プログラミング学習において最も大きな喜びの一つです。環境構築からファイアウォールの設定まで、ネットワークの知識も動員して自力で解決されたことは、非常に大きな自信になるはずです。

今回の成功のポイントまとめ
仮想環境(venv): 他の環境を汚さず、プロジェクト専用の部屋を作った。
FlaskとSQLAlchemy: データベースを連携させ、データを消えないようにした。
host=”0.0.0.0″: 自分のPCの中だけでなく、世界(ネットワーク)へ窓を開けた。
ファイアウォール許可: Windowsの「門番」に、Pythonの通信を許可させた。
これからの実用化に向けて
このメモ帳をさらに便利にするためのアイデアをいくつか置いておきます。
お気に入り登録: iPhoneのSafariでそのページを開いた状態で、下の「共有ボタン(四角から矢印が出ているアイコン)」から「ホーム画面に追加」を選択してください。
これで、スマホアプリと同じようにホーム画面のアイコンから一発で自分のメモ帳が起動するようになります。
デザインの調整: プログラム内の HTML_HEADER などの部分を書き換えるだけで、iPhoneで見た時の色や文字の大きさを自分好みに自由自在に変えられます。

自分のためだけの「世界に一つしかないツール」を、ぜひ存分に活用して、さらにプログラミングを楽しんでください。
数日間にわたる学習、本当にお疲れ様でした。今日はiPhoneで自分のメモを確認しながら、ゆっくりとお休みください!

再度の不具合 データーベース削除

スマホ対策で書き込みなどをしたあとに使っていたら、その後メモ帳6件の中身がすべて最初に作った同じメモ内容になっていました。新しく記録保存しても同様です。データーベースのエラーなのでしょうか?データーベースを消去して新しくやり直す方法などありますか?

メモがすべて同じ内容になってしまった原因は、データベース自体のエラーではなく、プログラム内の「常に1番のメモだけを操作する」という固定の処理が原因である可能性が高いです。
現在のプログラム(it = db.session.get(MemoItem, 1))は、どのメモを開いても「IDが1番のデータ」を取得して上書きするように指定されています。

1. 原因の箇所(app.py)
以下の部分を確認してください。

python
# メモの編集画面を出す --- (※3)
@app.route("/memo/<int:id>", methods=["GET", "POST"])
def memo(id: int):
# 原因はここ:引数の id を使わず「1」を固定で指定しています
it = db.session.get(MemoItem, 1)

これを、URLから送られてきた id を使うように修正する必要があります。

python
# 修正後:URLのid(0番, 1番, 2番...)に合わせて取得する
it = db.session.get(MemoItem, id)

2. データベースをリセット(消去)する方法
もしデータが混ざってしまい、一度きれいな状態からやり直したい場合は、以下の手順で簡単にリセットできます。
Flaskサーバーを停止(VS Codeで Ctrl + C)
データベースファイルを削除
エクスプローラーで、プログラムと同じフォルダにある memo.sqlite というファイルを右クリックして削除してください。
プログラムを再実行
再度 ▷ ボタンで実行すると、プログラム内の db.create_all() が働き、空の新しいデータベースファイルが自動作成されます。

3. プログラムの修正案(確実な動作のために)
IDの不整合を防ぐため、編集画面の関数を以下のように修正することをお勧めします。

python
@app.route("/memo/<int:id>", methods=["GET", "POST"])
def memo(id: int):
# URLのidで取得
it = db.session.get(MemoItem, id)

if it is None:
# 存在しないID、または新規作成(0)の場合
it = MemoItem(title="__無題__", body="")
if id != 0: # ID指定で存在しない場合も新規扱いにする
it.id = id

if request.method == "POST":
it.title = request.form.get("title", "__無題__")
it.body = request.form.get("body", "")
if it.title == "":
return "タイトルは空にできません"

# 新規保存(IDが未登録)の場合はaddが必要
if db.session.get(MemoItem, it.id) is None:
db.session.add(it)

db.session.commit()
return redirect(url_for("index"))

return render_template("memo.html", it=it)

まとめ
まずは memo.sqlite を削除してリセットしてみてください。
その上で、db.session.get(MemoItem, id) のように 1 ではなく id を使うように修正してください。
これで、1件ごとに独立した内容を保存できるようになります!

*****************************
データベースファイル(memo.sqlite)が instance というフォルダの中に作成されるのは、2025年現在の Flask-SQLAlchemy の標準的な仕様です。
データをリセット(消去)したい場合は、その instance フォルダの中にあるファイルを削除すればOKです。

1. データベースを消去してやり直す手順
VS Codeのターミナルで Ctrl + C を押し、Flaskを停止させます。
VS Codeの左側のファイル一覧(エクスプローラー)で、instance フォルダを開きます。
中にある memo.sqlite を右クリックして「削除」してください。
再度プログラムを ▷ 実行 すると、中身が空の新しいデータベースが自動的に作られます。

2. なぜ instance の中に作られるのか?
Flask-SQLAlchemy(バージョン 3.0以降)では、データベースなどの「環境ごとに変わるファイル」を、プログラム本体のコードと分けて管理するために、自動で instance フォルダを作るようになりました。

3. 前回の「すべてのメモが同じになる」問題の修正(重要)
リセットして新しくメモを書き始める前に、必ずプログラムの以下の部分を修正してください。ここを直さないと、また同じ現象が起きてしまいます。
【修正箇所: app.py】

python
@app.route("/memo/<int:id>", methods=["GET", "POST"])
def memo(id: int):
# 【ここを修正】 1 ではなく id に書き換える
it = db.session.get(MemoItem, id)

なぜ修正が必要か:
get(1) のままだと、どのメモ(0番、1番、2番…)を開いても、無理やり「1番」のデータを読み書きしてしまいます。
get(id) にすることで、選んだメモの番号(id)に合わせたデータを正確に扱えるようになります。
まとめ
消去: instance/memo.sqlite を削除。
修正: db.session.get(MemoItem, id) に書き換え。
これで、複数のメモを別々の内容で保存し、実用的に使い続けることができるようになります!

instanceの下にmemo,sqlitegaがあり削除しまして、db.session.get(MemoItem, id) に修正してうまく行きました。IDの不整合を防ぐ編集画面関数の修正は今度時間を取ってゆっくりやってみたいと思います。このまま少し使いこなし改善点など探していきたいと思います。ありがとうございました。

無事に解決して良かったです!
instance内のファイルをリセットし、idを正しく連動させたことで、ようやく「複数のメモを個別に管理できる」というアプリの基本形が完成しましたね。
今後の「使いこなし」に向けたヒント
しばらく使い込んでいく中で、以下のような改善ポイントが見つかるかもしれません。その時のためのヒントとして留めておいてください。
メモの並び順:
今はタイトル順(order_by(MemoItem.title))ですが、新しく書いたものが上に来るように「作成日時」などの項目をデータベースに追加したくなるかもしれません。
削除機能:
不要になったメモを削除するボタンがあると、より実用的になります。
検索機能:
メモが増えてくると、タイトルや本文からキーワード検索をしたくなるかもしれません。

ご自身で実際に使いながら「ここが不便だな」「こうなったら便利だな」と感じたことを一つずつ形にしていくのが、プログラミングの醍醐味です。
また何か気になったり、次のステップへ進みたくなったりしたときは、いつでもお気軽にご相談ください。自分だけの最強のメモ帳に育て上げていきましょう!
本日は本当にお疲れ様でした。

コメント