01. きっかけ
とある業務改善アプリを作ったんです。
でもね、サーバーとある機器との間にシリアル通信が入るのですが、http通信では通信が終わるまで画面更新できないという壁。
調べてみるとhttpではなくてWebsocketがいいらしい。とChatGPTが言ってました。
そこで、Wevsocketで通信させてテストしてみたらまぁいい感じなのよ。
はい。完全に備忘録として書きますデス。
「をいっ!それ如きの内容でいちいちQiitaかくなよっ!」ってツッコミをしようと思ったらここでやめといたほうが良いと思います。w
ということでやってみることにしました。
えっと、またシリーズものになりそうです。すみません。
それにしてもwebアプリ作ったり、マクロ書いたり、生成AIのファインチューニングしたり、スクラッチでDeepLearningモデル作ったり。俺、何者?
というか事務系の部署にいると理解のない上司のおかげで自由に色々やれる反面、何でもやらされるという・・・。笑
02. Websocketってなに?
こういうのこそ、Qiitaでしょ。
こんなページとか
こんなページ
もうみんな神だよね
ということで、ひとまずhttpで動くサーバーを作っていきます。
03. Djangoをインストール
まず、作業フォルダを作りましょう。
どこでもいいので、django-websocket-qiita
というフォルダを作ります。ぶっちゃけ、わかりやすければ何でもいいっす。
このフォルダの中で環境を作ります。
# mac/linux
python3 -m venv ws_env
source ws_env/bin/activate
# windows
# python -m venv ws_env
# ws_env/Script/activate
これで環境の中に入りました。ターミナルは以下のようになっているはず。
(ws_env) <folder path>:django-websocket-qiita$
pip install django
Djangoをインストールしましょう
今回は5.2がインストールされました。バージョン指定するときはpip install django==5.2
みたいに書くのはご存知だと思います。
04. プロジェクトを作る
そう、プロジェクトを作るんです。その中にアプリを作っていきます。
これがDjangoのルールです。多分
django-admin startproject websocket_proj
今回のプロジェクト名はwebsocket_porj
としてみました。
そうすると、プロジェクト名「websocket_proj」というフォルダができました。
この中にDjangoで使うファイルやフォルダが自動で生成されます。
websocket_proの中身はこんな感じ。websocket_projの中にまたwebsocket_projが存在します。(わかりにくいやん)
次にアプリを作ります。
python3 manage.py startapp strange_watch
実行後のフォルダ、ファイル構成はこちら
プロジェクトの下にstrange_watchというアプリができました。
ここでwebアプリを作っていきます。
ちなみに、プロジェクト名と同じ名前のwebsocket_projフォルダはいろんな設定をするためのフォルダなので後で触りますね。
05.setting.pyを設定する
ひとまず、httpでつながることを目指します。
ファイルはwebsocket_proj/websoketproj/setting.py
にあります。
- INSTALLED_APPSへの追記
setting.pyの中のINSTALLED_APPS
を編集します。先ほど作ったstrange_watch.apps.StrangeWatchConfigを追記します。
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'strange_watch.apps.StrangeWatchConfig', # 追記
]
ついでなので、このファイルを見てみましょう。
設定に記載した通り、strange_watch/apps.py
を開いてみます。
from django.apps import AppConfig
class StrangeWatchConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'strange_watch'
なにやらクラスが設定されていますね。strange_watch(アプリ名=フォルダ名)にはこのようなファイルがいくつか自動で生成されてます。
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
}
今回はデータベースを使わないので、DATABASEの中はすべてコメントアウトしておきます。
LANGUAGE_CODE = 'ja-JP' # 'en-us'
TIME_ZONE = 'Asia/Tokyo' # 'UTC'
念のため、言語コードとタイムゾーンを日本にしておきます。
06. 疎通確認
ターミナルで以下を打ち込みます。
cd websoket_proj # project名のフォルダ
ここで、ls(mac/Linux)、dir(Windows)とターミナルに入力すると、現在いるフォルダのファイルの一覧が表示されます。ここにmanage.py
があることを確認してから以下を実行します。
python manage.py runserver
# Watching for file changes with StatReloader
# Performing system checks...
#
# System check identified no issues (0 silenced).
# April 19, 2025 - 19:04:25
# Django version 5.2, using settings 'websocket_proj.settings'
# Starting development server at http://127.0.0.1:8000/
# Quit the server with CTRL-BREAK.
#
# WARNING: This is a development server. Do not use it in a production setting. # Use a production WSGI or ASGI server instead.
# For more information on production servers see: https://docs.djangoproject.com/en/5.2/howto/deployment/
ここでhttp://127.0.0.1:8000
にアクセスすると以下のような画面がでればOKです。
07. routing/html/処理を作成
Django独特なのかどうかわかりませんが、ルーティングをしなければいけません。
要はこのURLの要求があれば、Djangoの中のどのファイルを参照しろ~みたいなルーティングです。
おきまりの作法みたいなもんですが、ちゃんと読めば何やっているのかは理解できるはず
07-1. websokcet_proj/strange_watch/views.pyを作る
最終的にここからhtmlを返す処理をここに書きます。そして、ここにリクエストが来て、htmlをブラウザに返すようにルーティングします。
from django.shortcuts import render
# Create your views here. ここまでは自動で作られています。以下追加
from django.http import HttpResponse
# add
def index(request):
return HttpResponse('''<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Page</title>
</head>
<body>
<h1>Test page dayo!</h1>
</body>
</html>''')
HttpResponseクラスを使うと、文字列をhtmlにてをブラウザに送り付けてくれます。
テスト用???
07-2 websokcet_proj/strange_watch/urls.pyの作成と編集
strange_watchアプリフォルダの中にはurls.pyがありません。アプリを作った時に自動生成してくれれば嬉しいんですけど、他にもルーティングの方法があるんでしょうか?
ファイルを新規作成し、ルーティングを記載します。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
]
ポートの後ろに何もないurlが来た時には、先ほど書いたviews.pyのindex関数に紐づけられます。
そう、さっき作ったやつです。
使うためにはfrom . import views
でインポートしておく必要があります。
07-3. websokcet_proj/websocket_proj/urls.pyの編集
さらにこのDjangoサーバーのおおもとにwebsokcet_proj/strange_watch/urls.py
を紐づける必要があります。
from django.contrib import admin
from django.urls import path, include
import strange_watch
import strange_watch.urls # 追記
urlpatterns = [
# path('admin/', admin.site.urls), # コメントアウト
path('', include(strange_watch.urls)), # 追記,
]
設定したポートに接続されると、ここに来ます。
この時にstrange_watch
アプリのurls.py
ファイルも参照しろよ!というおまじないです。
最初のviews.py
を書くと、vscodeなどではどんどん保管されてくるのでタイポが減るのでこの順序で書くのがおすすめです。
ではサーバーを起動して、ブラウザから127.0.0.1:8000にアクセスしてみましょう。
h1タグでこれが表示できたらOKデス。
08. htmlをテンプレートフォルダにまとめる
Djangoはアプリフォルダ内にテンプレートフォルダを作ってそこにhtmlやcssなどを置くのが基本のようです。
先ほどはviews.pyのindex関数からhtmlを送っていましたが、そもままではvscodeなどの高機能エディタで編集する時にいろんな機能が使いにくいです。はい、補完機能全力で使ってます!GitHub Copilotも最近使い始めました。
そのため、htmlを一つのフォルダの中に保存し、管理しやすくするのが普通みたいです。まずはstrange_watch
フォルダの中にtemplates
フォルダを作ります。
さらにここにindex.html
ファイルを作ります。
08-1. htmlファイルに書き込む
ファイルには適当にhtmlを書き込みます。テストなんで。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Page</title>
</head>
<body>
<h1>Test page Yheaaaaaa!!</h1>
<h2>WebSocket Test</h2>
<div id="correct_watch">時計表示部分</div>
</body>
</html>
まぁ、内容は適当に・・・
08-2. setting.pyを修正
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['./strange_watch/templates'], # 修正
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
テンプレートのディレクトリを指定します。要はhtmlをファイルを保存する場所です。
え?ここで指定するの?って感じがしますね。w
08-3. アプリ(strange_watch)のviews.pyの修正
from django.shortcuts import render
# Create your views here.
# add
def index(request):
return render(request, 'index.html')
render関数は、08-1で指定したフォルダの中から、templetesフォルダ内にある第二引数の名前のhtmlファイルをブラウザに送信してくれるみたいです。
08-4. ルーティングを修正
またしてもwebsoxket_proj内とstrange_watch内のルーティングを修正します。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('index.html', views.index)),
]
ポート番号の後ろに何もなくても、index.htmlがあってもいいよにしとこ
ま、テスト何でなんでもいい。ちょっと試したかっただけ。笑
ブラウザの検索ウインドウに
http://127.0.0.1:8000
http://127.0.0.1:8000/index.html
いずれでも同じページが表示されるようにルーティングしておきます
from django.contrib import admin
from django.urls import path, include
import strange_watch.urls # 追記
urlpatterns = [
# path('admin/', admin.site.urls), # コメントアウト
path('', include(strange_watch.urls)), # 追記,
path('index', include(strange_watch.urls)), # 追記,
]
こっちも同様の目的で追記します。
08-5. サーバー起動して確認
127.0.0.1:8000/index.html(/index.html無しも同じ。)にアクセスしてこのページがでたらOKです。
あ、よく考えたらhttpやってるのに「WebSocket Test」って意味わからんっすね。すまん
09. サーバー時刻をブラウザで受け取る機能を実装
http通信でhtmlを送ってブラウザで表示することができました。
次hブラウザでボタンが押されたら、http通信でサーバーに要求を出して、サーバーから時刻を返すことをやりたいと思います。
09-1. views.pyに関数を作る
import datetime
from django.http import JsonResponse
def get_server_time(request):
current_time = datetime.datetime.now()
current_time = current_time.strftime("%H:%M:%S")
data = {
'current_time': current_time,
}
print(data)
return JsonResponse(data)
views.pyにこれを書き加えます。書き換えじゃないです。追記です。この関数からサーバー時間をブラウザに返します。
09-2. ルーティングの修正
面倒ですが、ルーティングを直します。ポート番号の後に、get_current_time
という文字がついていた時のルーティングを作ります。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('index.html', views.index)),
path('get_current_time/', views.get_current_time),
]
get_current_time
がポート番号の後についていたら、vews.pyのget_current_time関数に飛ばします。
from django.contrib import admin
from django.urls import path, include
import strange_watch.urls # 追記
urlpatterns = [
# path('admin/', admin.site.urls), # コメントアウト
path('', include(strange_watch.urls)), # 追記,
path('index', include(strange_watch.urls)), # 追記,
path('get_current_time/', include(strange_watch.urls)), # 追記
]
websocket_projのurls.pyも追記します。
get_current_time
の文字があってもstrange_watch.urls.pyにルーティングさせるよう追記です。
ここまでやってくると、二つのurls.pyの意味が分かってきますね。
全体のルーティングはwebsocket_proj/urls.pyが担い、各アプリのルーティングはアプリ内のurls.pyが担うって感じですかね。
09-3. htmlを修正する
大幅に修正するので(といっても追記ですが・・)、全体を載せておきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Page</title>
</head>
<body>
<h1>Test page Yheaaaaaa!!</h1>
<h2>WebSocket Test</h2>
<!-- 追記部分・・・ここから -->
<span> <!-- 時計表示部分 -->
<p id="correct_watch">時計表示部分</p>
<button id="correct_time">現在時刻取得</button>
</span>
<script> // ここからJavaScript
let current_watch = document.getElementById("correct_watch");
let get_correct_watch_button = document.getElementById("correct_time");
// ボタンが押されたときに動く関数
get_correct_watch_button.addEventListener("click", function(e) {
get_correct_time(e);
});
// ボタンが押されたときの処理関数
const get_correct_time = function(e) {
console.log("ボタンが押されました");
let url = 'get_current_time';
fetch(url)
.then(response => response.json())
.then(data => {
console.log(data);
current_watch.textContent = data.current_time;
})
.catch(error => {
console.error('Error:', error);
});
};
</script>
<!-- 追記部分・・・ここまで -->
</body>
</html>
09-4. 試してみる
サーバーを再起動してアクセスしてみます。
時計表示部分とボタンが出現しました。
ではボタンをポチリます。
いゃぁぁぁぁぁぁぁ!
サーバーの時間が戻ってきてます。
サーバーを立ち上げたコマンドプロンプトを見てみまます。
301が帰ってきているのはなんでだろ?
わかんないので、これはまた調べよう。というか、どなたか、教えてください。
Webや通信は苦手・・・
10. 終わりに・・・
ひとまずhttp通信ができました。目的はwebsocket通信なので、今はまだ道半ばです。
いきなりwebsocket通信をやってもイマイチ良さが理解できなかったので一旦http通信をおさらいしました。
次はいよいよWebSocket化していきます。
つづく