Gemini先生と一緒にPythonを勉強する3日目です。
前回作成した「Webブラウザでアクセスした時の時間を表示するサービス」に、リアルタイムの時間を表示し続ける時計サービスに機能を強化したいと思います。
【Pythonの学習 Day2】現在の時刻を表示するサービスを作ってみる: https://vpslife.server-memo.net/python_study_day_02
プロジェクトのディレクトリ内容と仮想環境の有効化
前回から引き続きとなりますが、今回使用するプロジェクトのディレクトリ「~/project/time_app/」の構成を、「tree」コマンドで表示しておきます。
$ tree ~/project/time_app /home/tamohiko/project/time_app ├── templates │ └── time.html └── time_app.py
開発を再開する前に仮想環境を有効化しておきます。
$ source ~/project/time_app/.venv/bin/activate
リアルタイムに日時を表示したい!Gemini先生、どうすれば?
とりあえず、いつものようにGemini先生に「リアルタイムで日時を表示するにはどうしたらいい?」と質問してみると、「それならJavaScriptが必要になりますね」との教えてくれました。
最初は、テンプレートファイルである「templates/time.html」に、直接「JavaScript」を書き込む方法を教えてもらいました。
でも、よくよく考えてみると、JavaScriptのコードをHTMLファイルから独立させた方が、後々のメンテナンスや機能追加(改造)がしやすそうな気がしました。
そこで、Gemini先生に「JavaScriptって別ファイルにできますか?」と再度聞いてみたところ、「もちろん可能ですよ!」という心強いお返事。というわけで、JavaScriptは別ファイルに分けて開発を進めることに決定しました。
ちなみに、学習のメインであるPythonプログラムファイル「time_app.py」については、今回は特に変更なしとのことでした。(Pythonの勉強をしているのに今回は出番無しなのです…)
いよいよJavaScript作成!Flaskのお作法とGemini先生のアドバイス
Gemini先生によると、JavaScriptファイルは「static」ディレクトリ内に配置するのがFlaskの慣習だそうです。
そこで今回は、「~/project/time_app/static/js」というディレクトリを作り、そこに「realtime_clock.js」という名前でJavaScriptファイルを作成することにしました。
$ mkdir -p ~/project/time_app/static/js $ cd ~/project/time_app/static/js $ vi realtime_clock.js
ファイルの内容は、Gemini先生が教えてくれたコードをそのまま記述しました。
JavaScriptのコード内容については、Pythonの勉強がメインなので今回詳しく触れません。
// リアルタイムで時刻を更新する関数
function updateRealTimeClock() {
// 現在の日時をJavaScriptで取得
const now = new Date();
// Pythonのstrftimeの書式に合わせて整形
const year = now.getFullYear();
// getMonth() は 0 から始まるので +1 する。padStartで2桁表示にする。
const month = (now.getMonth() + 1).toString().padStart(2, '0');
const day = now.getDate().toString().padStart(2, '0');
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
// 表示する文字列を作成
const timeString = `${year}年${month}月${day}日 ${hours}時${minutes}分${seconds}秒`;
// id="realtime-clock" の要素のテキストを更新
const clockElement = document.getElementById('realtime-clock');
if (clockElement) { // 要素が存在するか確認
clockElement.textContent = timeString;
}
}
// 1秒ごと (1000ミリ秒) に updateRealTimeClock 関数を実行
setInterval(updateRealTimeClock, 1000);
// ページ読み込み完了時にも一度実行して、すぐにJavaScriptでの時刻表示に切り替える
// (サーバーからの時刻とのラグを最小限にするため)
// DOMContentLoadedイベントは、HTMLの読み込みと解析が完了した時点で実行します
document.addEventListener('DOMContentLoaded', function() {
updateRealTimeClock(); // 初回実行
});
HTMLテンプレートも更新!JavaScriptを読み込ませよう
作成したJavaScriptファイル「realtime_clock.js」を、いよいよHTMLテンプレート「templates/time.html」から読み込んで、実際に動くようにしていきます!
time.htmlのバックアップを行ってから、編集作業を行っていきます。
$ cd ~/project/time_app/templates/ $ cp -p time.html time.html_org $ vi time.html
変更箇所は赤字の部分となります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>リアルタイム時刻表示</title>
<script src="{{ url_for('static', filename='js/realtime_clock.js') }}" defer></script>
<style>
body { font-family: sans-serif; text-align: center; margin-top: 50px; }
h1 { color: #333; }
p { font-size: 2em; color: #555; }
</style>
</head>
<body>
<h1>現在の時刻</h1>
<p id="realtime-clock">{{ current_time }}</p>
</body>
</html>
追加したコードの解説
追加した内容についてGemini先生に教えてもらいました。
<script src="{{ url_for('static', filename='js/realtime_clock.js') }}" defer></script>
<script ...></script>
これは、これからこのHTMLファイルでJavaScriptを使いますとブラウザに伝えるためのHTMLタグです。
src="..."
srcは読み込むJavaScriptファイルがどこにあるかを指定する属性で、ここにファイルの場所を記述します。
{{ url_for('static', filename='js/realtime_clock.js') }}
ここがFlaskを使う上でのポイントで、{{ }}(二重波括弧)はFlaskで使用するテンプレートエンジン「Jinja2」の特殊な記号で、この括弧の中はPythonのコードとして解釈して、その結果をここに埋め込んで使用することを宣言しています。
url_for()
これはFlaskが提供している関数で、指定したファイルやプログラムの場所に対応する「正しいURLを自動的に作ってくれる」機能です。
'static', filename='js/realtime_clock.js'
'static': Flaskでは、画像やCSSファイル、そして今回のJavaScriptファイルのような「静的ファイル」を置くための特別なディレクトリ(デフォルトでは「static」という名前)を指定しています。
「'static'」と書くことで、「static」フォルダの中を探してくださいと指定しています。
filename='js/realtime_clock.js': これは「static」ディレクトリの中にある、「js」というサブディレクトリにある「realtime_clock.js」ファイルを指定しています。
直接「realtime_clock.js」と指定しない理由
もし、将来ウェブサイトのURL構成が変わったとしても、url_for を使っていればFlaskが自動で新しい正しいURLを生成してくれるため、リンク切れとなるリスクが減るためです。
defer
JavaScriptファイルを読み込んで実行するタイミングを調整するための指示している。
「defer」を付けておくと、ブラウザは以下のように賢く動いてくれます。
- まずHTMLページ全体の解析を行います。(JavaScriptファイルのダウンロードでHTMLの表示が止まらない!)
- HTMLの解析と並行して、裏側でこのJavaScriptファイル (realtime_clock.js) をダウンロードします。
- HTMLページ全体の構造解析が全部出来上がってから(専門用語で言うとDOMの構築完了後)、ダウンロードしておいたJavaScriptコードを実行します。
これにより、ユーザーはページの表示がブロックされることなく、快適にコンテンツを閲覧することができるわけです。
<p id="realtime-clock">{{ current_time }}</p>
HTML側では、時刻を表示したい<p>タグにid属性を使って、「id="realtime-clock"」という名前をつけています。
この名前を使って、JavaScriptから特定のHTML要素を簡単に見つけ出し、操作できるようになります。
{{ current_time }} は、最初にページが表示されたときにPython側から渡されるサーバの日時ですが、JavaScriptが動き出したら、この<p>タグの中身をリアルタイムで更新していくことになります。
JavaScript側ではどうやってこのid属性を使うのか?
JavaScript「realtime_clock.js」のコードの中に「document.getElementById('realtime-clock')」という部分があります。
これは、HTML文書全体(document)の中から、「realtime-clock」というID(id)を持つ要素(Element)を探す(get)という意味の命令です。
この命令によって、JavaScriptは「時刻を表示するのは、「realtime-clock」という名前が付いた<p>タグである」と正確に場所を特定し、その中身 (.textContent) を新しい時刻 (timeString) に書き換えることができます。
// id="realtime-clock" の要素のテキストを更新
const clockElement = document.getElementById('realtime-clock');
if (clockElement) { // 要素が存在するか確認
clockElement.textContent = timeString;
}
ついに実行!リアルタイム時計は動くのか?
JavaScriptファイルの「realtime_clock.js」の作成と、HTMLテンプレートである「time.html」の編集が終わったので、いよいよPythonのプログラムである「time_app.py」を実行して本当にリアルタイムで時刻が表示されるのかを確認してみます!
$ python ./time_app.py * Serving Flask app 'time_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:5000 Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 787-176-237
Webブラウザで「http://localhost:5000/」 にアクセスして動作確認を行います。
無事、現在の時刻がリアルタイムで表示され続けています!!
これが最初思い浮かべていた「Webページで動的に変わる時計」です!
素朴な疑問:「全部Pythonでできないの?」Gemini先生に聞いてみた!
さて、今回のリアルタイム時計を表示する作業って、JavaScriptの作成とHTMLテンプレートの修正だけでしたが、これって全部Pythonだけで時刻をリアルタイム更新できないかと疑問に思いGemini先生に出来るかどうかを聞いてみました。
その時の解答が以下のとおりでした。
結論から申し上げますと、Webブラウザ上でユーザーが見ている画面の時刻をPythonのみで直接リアルタイムに更新し続けるのは、Webの基本的な仕組み上、難しい、あるいは標準的なアプローチではありません。
どうやら、無理っぽいですね…
なぜPythonだけでは難しいの?Gemini先生の解説
Python (今回使っているFlaskも含む) の役割は、主にサーバーサイドで動作しリクエストに応じてHTMLを生成するという処理を担当しています。
そのため、一度HTMLがブラウザに送信されてしまうと、既にブラウザが表示しているページの内容をリアルタイムで直接書き換えることは、基本的にできません。
リアルタイムで時刻を表示するということは、一度ページが表示された後も継続的に時刻表示部分を更新し続ける必要があります。
もしPythonだけでこれを実現しようとするとどうなるか?
例えば「1秒ごとにページ全体をサーバーにリクエストし直して、新しいHTMLを受け取って再描画する」というような方法が考えられますが、これは非常に効率が悪く、画面がチカチカしてユーザー体験も著しく損なわれまいます。
なので、これは現実的なリアルタイム表示とは言えません。
ただし、Webブラウザを介さないGUIアプリケーション(例えばPythonのTkinterやPyQtで作るデスクトップアプリ)であれば、Pythonのコードだけでウィンドウ内の表示をリアルタイムに更新が可能です。
今日の学習まとめ:リアルタイム時計で学んだこと!
Gemini先生とのPython学習3日目、Webページにリアルタイムで動き続ける時計を実装することに挑戦しました!
今回の学習を通して、主に以下のことができるようになり、理解が深まりました。
- JavaScriptによるリアルタイム更新: JavaScriptを使うことで、ブラウザの表示をリアルタイムに書き換えることができるのを学びました。
- FlaskでのJavaScript連携:FlaskプロジェクトではJavaScriptファイルを「static」ディレクトリに格納するの慣習となっていて、「url_for()」関数を使用することでHTMLから読み込むことができる。
-
HTMLとJavaScriptの連携技術:
- <script>タグでのJavaScriptファイルの読み込みと、「defer」属性による実行タイミングの調整。
- HTML要素に「id」属性を付けて、JavaScriptから特定の要素をピンポイントで操作する方法。
- Web開発の仕組み: Webページのリアルタイム更新にはJavaScriptが適していて、Python(サーバーサイド)だけでは難しい理由(サーバーとブラウザの役割分担)を学びました。
Python自体のコーディングはありませんでしたが、Webアプリケーションを動的にするための重要な要素を学ぶことができたので、今後に役立ちそうです。
今後の予定
次に追加したいものとしは、背景をつけてるのと、時間毎に背景を変更するという機能なので、次回はそれについて勉強していこうと思います。
コメント