0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DjangoでWebsocketしたい 01 ~まずはhttp通信~

Last updated at Posted at 2025-04-19

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としてみました。


スクリーンショット 2025-04-14 23.29.54.png

そうすると、プロジェクト名「websocket_proj」というフォルダができました。
この中にDjangoで使うファイルやフォルダが自動で生成されます。


スクリーンショット 2025-04-14 23.31.22.png

websocket_proの中身はこんな感じ。websocket_projの中にまたwebsocket_projが存在します。(わかりにくいやん)


次にアプリを作ります。

python3 manage.py startapp strange_watch

実行後のフォルダ、ファイル構成はこちら

スクリーンショット 2025-04-14 23.44.54.png

プロジェクトの下にstrange_watchというアプリができました。
ここでwebアプリを作っていきます。

ちなみに、プロジェクト名と同じ名前のwebsocket_projフォルダはいろんな設定をするためのフォルダなので後で触りますね。

05.setting.pyを設定する

ひとまず、httpでつながることを目指します。
ファイルはwebsocket_proj/websoketproj/setting.pyにあります。


  • INSTALLED_APPSへの追記
    setting.pyの中のINSTALLED_APPSを編集します。先ほど作ったstrange_watch.apps.StrangeWatchConfigを追記します。
setting.py
# 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を開いてみます。

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です。

画像3.png



07. routing/html/処理を作成

Django独特なのかどうかわかりませんが、ルーティングをしなければいけません。
要はこのURLの要求があれば、Djangoの中のどのファイルを参照しろ~みたいなルーティングです。
おきまりの作法みたいなもんですが、ちゃんと読めば何やっているのかは理解できるはず


07-1. websokcet_proj/strange_watch/views.pyを作る

最終的にここからhtmlを返す処理をここに書きます。そして、ここにリクエストが来て、htmlをブラウザに返すようにルーティングします。


websokcet_proj/strange_watch/views.py
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がありません。アプリを作った時に自動生成してくれれば嬉しいんですけど、他にもルーティングの方法があるんでしょうか?
ファイルを新規作成し、ルーティングを記載します。

websokcet_proj/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を紐づける必要があります。

websokcet_proj/websocket_proj/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にアクセスしてみましょう。
タイトルなし.png

h1タグでこれが表示できたらOKデス。


08. htmlをテンプレートフォルダにまとめる

Djangoはアプリフォルダ内にテンプレートフォルダを作ってそこにhtmlやcssなどを置くのが基本のようです。
先ほどはviews.pyのindex関数からhtmlを送っていましたが、そもままではvscodeなどの高機能エディタで編集する時にいろんな機能が使いにくいです。はい、補完機能全力で使ってます!GitHub Copilotも最近使い始めました。
そのため、htmlを一つのフォルダの中に保存し、管理しやすくするのが普通みたいです。まずはstrange_watchフォルダの中にtemplatesフォルダを作ります。
さらにここにindex.htmlファイルを作ります。

タイトルなし.png

08-1. htmlファイルに書き込む

ファイルには適当にhtmlを書き込みます。テストなんで。

index.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を修正

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の修正

websokcet_proj/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内のルーティングを修正します。

websokcet_proj/strange_watch/urls.py
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
いずれでも同じページが表示されるようにルーティングしておきます


websokcet_proj/websocket_proj/urls.py
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です。

タイトルなし.png

あ、よく考えたらhttpやってるのに「WebSocket Test」って意味わからんっすね。すまん



09. サーバー時刻をブラウザで受け取る機能を実装

http通信でhtmlを送ってブラウザで表示することができました。
次hブラウザでボタンが押されたら、http通信でサーバーに要求を出して、サーバーから時刻を返すことをやりたいと思います。


09-1. views.pyに関数を作る

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という文字がついていた時のルーティングを作ります。

websokcet_proj/strange_watch/urls.py
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関数に飛ばします。

websokcet_proj/websocket_proj/urls.py
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を修正する

大幅に修正するので(といっても追記ですが・・)、全体を載せておきます。

index.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. 試してみる

サーバーを再起動してアクセスしてみます。

タイトルなし.png

時計表示部分とボタンが出現しました。
ではボタンをポチリます。

タイトルなし2.png

いゃぁぁぁぁぁぁぁ!

サーバーの時間が戻ってきてます。
サーバーを立ち上げたコマンドプロンプトを見てみまます。

タイトルなし.png

301が帰ってきているのはなんでだろ?
わかんないので、これはまた調べよう。というか、どなたか、教えてください。
Webや通信は苦手・・・

10. 終わりに・・・

ひとまずhttp通信ができました。目的はwebsocket通信なので、今はまだ道半ばです。
いきなりwebsocket通信をやってもイマイチ良さが理解できなかったので一旦http通信をおさらいしました。
次はいよいよWebSocket化していきます。

つづく

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?