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?

More than 1 year has passed since last update.

DjangoとDocker練習OA24o1o0 ゲーム対局部屋をモニターしよう!

Last updated at Posted at 2022-06-11

サンプルを見る

📖 この記事のゴール

目標

ゲーム対局部屋をモニターしたい

  • 一手指す毎に
    • 盤面を、現盤面で上書きする
    • 棋譜に1手分追加する

情報

この記事は Lesson 1. から順に全部やってこないと ソースが足りず実行できないので注意されたい

What is This is
Lesson 1. 📖 DjangoとDockerでゲーム対局サーバーを作ろう!

この記事のアーキテクチャ:

What is This is
OS Windows10
Container Docker
Database Postgresql, (Redis)
Program Language Python 3
Web framework Django
Auth allauth
Frontend Vuetify
Data format JSON
Others (Socket), Web socket
Editor Visual Studio Code (以下 VSCode と表記)

ディレクトリ構成を抜粋すると 以下のようになっている

    ├── 📂 src1                            # あなたのDjangoサーバー開発用ディレクトリー。任意の名前
    │   ├── 📂 apps1
    │   │   ├── 📂 accounts_vol1o0    # アプリケーション
    │   │   ├── 📂 portal_v1                # アプリケーション
    │   │   ├── 📂 practice_vol1o0              # アプリケーション
    │   │   │   ├── 📂 migrations
    │   │   │   └── 📂 models
    │   │   │       └── 📂 room
    │   │   │           └── 📄 ver1o0.py
    │   │   ├── 📂 tic_tac_toe_vol1o0           # アプリケーション
    │   │   └── 📂 tic_tac_toe_vol2o0           # アプリケーション
    │   │       ├── 📂 migrations
    │   │       │   └── 📄 __init__.py
    │   │       ├── 📂 static
    │   │       │   └── 📂 tic_tac_toe_vol2o0
    │   │       │       ├── 📂 gui
    │   │       │       └── 📂 think
    │   │       ├── 📂 templates
    │   │       │   └── 📂 tic_tac_toe_vol2o0
    │   │       │       ├── 📂 gui
    │   │       │       └── 📂 think
    │   │       ├── 📂 views
    │   │       │   ├── 📂 gui
    │   │       │   └── 📂 think
    │   │       ├── 📄 __init__.py
    │   │       ├── 📄 admin.py
    │   │       ├── 📄 apps.py
    │   │       └── 📄 tests.py
    │   ├── 📂 data
    │   ├── 📂 project1                     # プロジェクト
    │   │   ├── 📄 __init__.py
    │   │   ├── 📄 asgi.py
    │   │   ├── 📄 settings_secrets_example.txt
    │   │   ├── 📄 settings.py
    │   │   ├── 📄 urls_accounts_vol1o0.py
    │   │   ├── 📄 urls_practice.py
    │   │   ├── 📄 urls_tic_tac_toe_v1.py
    │   │   ├── 📄 urls_tic_tac_toe_v2.py
    │   │   ├── 📄 urls.py
    │   │   ├── 📄 ws_urls_tic_tac_toe_v1.py
    │   │   └── 📄 wsgi.py
    │   ├── 📂 project2                     # プロジェクト
    │   ├── 🐳 docker-compose-project2.yml
    │   ├── 🐳 docker-compose.yml
    │   ├── 🐳 Dockerfile
    │   ├── 📄 manage.py
    │   └── 📄 requirements.txt
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📄 urls.py
    ├── 📂 src2_local                      # Djangoとは関係ないもの
    │    ├── 📂 sockapp1
    │    └── 📂 websockapp1
    └── 📄 .gitignore

実装手順

Step [OA24o1o0g1o0] Dockerコンテナの起動

👇 (していなければ) Docker コンテナを起動しておいてほしい

# docker-compose.yml ファイルを置いてあるディレクトリーへ移動してほしい
cd src1

# Docker コンテナ起動
docker-compose up

Step [OA24o1o0g2o0]

Merged to OA24o1o0g3o0

Step [OA24o1o0g3o_1o0] Moveメッセージ・ハンドラー

👇 以下のファイルを新規作成してほしい

    └── 📂 src1
        └── 📂 apps1
            └── 📂 tic_tac_toe_vol3o0                 # アプリケーション
                └── 📂 websocks
                    └── 📂 gui
                        └── 📂 c2s_handlers
                            └── 📂 move
👉                              └── 📄 ver1o0.py
# BOF [OA24o1o0g3o_1o0]

from asgiref.sync import sync_to_async

# 部屋モデル
from apps1.practice_vol1o0.models.room.ver1o0 import Room
#          ---------------             ------        ----
#          11                          12            2
#    ----------------------------------------
#    10
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれる __init__.py ファイルにさらに含まれるクラス

# [OA16o3o_2o0g1o_2o0] Movedメッセージ
from apps1.tic_tac_toe_vol2o0.views.msg.s2c_json_gen.messages.moved.ver1o0 import MovedS2cMessage


class MoveC2sHandler:
    """駒を置いたとき"""

    async def on_message_received(self, scope, doc_received):
        """メッセージ受信"""

        # ログインしていなければ AnonymousUser
        user = scope["user"]
        # print(
        #     f"[TicTacToeV3o1o0ConsumerCustom on_move 1] user=[{user}] doc_received={doc_received}")
        if user.is_anonymous:
            # ログインしていないユーザーの操作は記録しません
            # print(
            #    f"[TicTacToeV3o1o0ConsumerCustom on_move 1.5] ログインしていないので操作の記録を省きます")
            pass

        else:

            # print(f"[TicTacToeV3o1o0ConsumerCustom on_move 1.75] ログインしています")

            # 部屋名
            #
            # * URLのパスに含まれている
            room_name = scope["url_route"]["kwargs"]["kw_room_name"]
            # print(f"[TicTacToeV3o1o0ConsumerCustom on_move 2] scope={scope}")

            # イベント名 (Client to server)
            event = doc_received.get("event", None)
            # 駒を置いたマス番号
            sq = doc_received.get("sq", None)
            # 駒を置いた方の X か O
            piece_moved = doc_received.get("piece", None)
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 3] クライアントからのメッセージを受信しました room_name=[{room_name}] event=[{event}] piece_moved=[{piece_moved}] sq=[{sq}]")
            # クライアントからのメッセージを受信しました room_name=[Elephant] event=[C2S_Moved] piece_moved=[X] sq=[2]

            # 部屋取得
            room = await get_room_by_name(room_name)

            # (デバッグ)現状を出力
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 4] room=[{room}]")
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 5] now room.name=[{room.name}] room.board=[{room.board}] room.record=[{room.record}]")

            # 駒を置きます
            #
            # * 盤が9マスになるように右を '.' で埋めます
            room.board = room.board.ljust(9, '.')
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 6] now2 room.board=[{room.board}]")

            room.board = f"{room.board[:sq]}{piece_moved}{room.board[sq+1:]}"
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 7] now3 room.board=[{room.board}]")

            # 棋譜を書きます
            #
            # * 相手が AnonymousUser なら、相手の指し手が記録されていないものになります
            # * 9文字を超えるようなら、切り捨てます

            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 8] now4 room.record=[{room.record}]")
            room.record = f"{room.record}{sq}"[:9]
            print(
                f"[TicTacToeV3o1o0ConsumerCustom on_move 9] now5 room.record=[{room.record}]")

            # 部屋を上書きします
            await save_room(room)

            print(f"[TicTacToeV3o1o0ConsumerCustom on_move 10] saved")

        # Client to server
        sq = doc_received.get("sq", None)
        piece_moved = doc_received.get("piece", None)
        # print(
        #     f"[TicTacToeV3o1o0ConsumerCustom on_move 11] C2S_Moved sq=[{sq}] piece_moved=[{piece_moved}]")

        args = {
            "sq1": sq,
            "piece1": piece_moved,
        }

        return MovedS2cMessage(args).asDict()


@sync_to_async
def get_room_by_name(name):
    # FIXME 部屋名はIDではないので、先頭の要素を取得
    return Room.objects.filter(name=name)[0]


@sync_to_async
def save_room(room):
    room.save()

# EOF [OA24o1o0g3o_1o0]

Step [OA24o1o0g3o0] Webソケットの通信プロトコル作成 - consumer_custom/v1o0.py ファイル

👇 以下のファイルを新規作成してほしい

    └── 📂 src1
        └── 📂 apps1
            └── 📂 tic_tac_toe_vol3o0                 # アプリケーション
                └── 📂 websocks
                    └── 📂 consumer_custom
👉                      └── 📄 ver1o0.py
# BOF [OA24o1o0g3o0]

# 〇×ゲーム2.0巻 ウェブソケットGUIコンシューマー1.0版
from apps1.tic_tac_toe_vol2o0.websocks.gui.consumer.ver1o0 import ConsumerBase
#                         ^two
#          ------------------                       ------        ------------
#          11                                       12            2
#    -----------------------------------------------------
#    10
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれている __init__.py ファイルにさらに含まれるクラス

# 〇×ゲーム2.0巻 ウェブソケットGUIメッセージ駆動1.0版
from apps1.tic_tac_toe_vol2o0.websocks.gui.message_manager.ver1o0 import MessageManager
#          ------------------                              ------        --------------
#          11                                              12            2
#    ------------------------------------------------------------
#    10
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれる __init__.py にさらに含まれるクラス

# [OA16o3o0gA10o_1o0] 〇×ゲーム2.0巻 - WebソケットGUI Endメッセージハンドラー 1.0版
from apps1.tic_tac_toe_vol2o0.websocks.gui.c2s_handlers.end.ver1o0 import EndC2sHandler

# [OA24o1o0g3o_1o0] 〇×ゲーム3.0巻 - WebソケットGUI Moveメッセージハンドラー 1.0版
from apps1.tic_tac_toe_vol3o0.websocks.gui.c2s_handlers.move.ver1o0 import MoveC2sHandler
#                         ^

# [OA16o3o0gA10o_3o0] 〇×ゲーム2.0巻 - WebソケットGUI Startメッセージハンドラー 1.0版
from apps1.tic_tac_toe_vol2o0.websocks.gui.c2s_handlers.start.ver1o0 import StartC2sHandler


class TicTacToeV3o1o0ConsumerCustom(ConsumerBase):
    """OA24o1o0g3o0 Webソケット用コンシューマー"""

    def __init__(self):
        super().__init__()
        self._messageManager = MessageManager()
        self._messageManager.addMessageHandler('C2S_End', EndC2sHandler())
        self._messageManager.addMessageHandler('C2S_Moved', MoveC2sHandler())
        self._messageManager.addMessageHandler('C2S_Start', StartC2sHandler())

    async def on_receive(self, doc_received):
        """クライアントからメッセージを受信したとき

        Returns
        -------
        response
        """

        return await self._messageManager.execute(self.scope, doc_received)

# EOF [OA24o1o0g3o0]

Step [OA24o1o0g4o0] Webソケット用ルート新規作成 - ws_urls_tic_tac_toe_v3.py ファイル

👇 以下のファイルを新規作成してほしい

    └── 📂 src1
        ├── 📂 apps1
        │   └── 📂 tic_tac_toe_vol3o0               # アプリケーション
        │       └── 📂 websocks
        │           └── 📂 consumer_custom
        │               └── 📄 ver1o0.py
        └── 📂 project1                         # プロジェクト
👉          └── 📄 ws_urls_tic_tac_toe_v3.py    # Three
# BOF OA24o1o0g4o0

# See also: 📖 [Channels - Consumers](https://channels.readthedocs.io/en/latest/topics/consumers.html)
from django.conf.urls import url

# 〇×ゲームの練習 v3.1
from apps1.tic_tac_toe_vol3o0.websocks.consumer_custom.ver1o0 import TicTacToeV3o1o0ConsumerCustom
#                         ^three
#          ------------------                          ------        -----------------------------
#          11                                          12            2
#    -------------------------------------------------
#    10
# 10. ディレクトリー
# 11. アプリケーション
# 12. Python ファイル。拡張子抜き
# 2. クラス名


websocket_urlpatterns = [

    # OA24o1o0g4o0 〇×ゲームの練習3.0巻 3.3版
    url(r'^tic-tac-toe/v3.3/playing/(?P<kw_room_name>\w+)/$',
        #                 ^three
        # -------------------------------------------------
        # 1
        TicTacToeV3o1o0ConsumerCustom.as_asgi()),
    #   ---------------------------------------
    #   2
    # 1. 例えば `ws://example.com/tic-tac-toe/v3.3/playing/Elephant/` のようなURLのパスの部分
    #                            ----------------------------------
    #    kw_room_name は変数として渡される
    # 2. クラス名とメソッド。 URL を ASGI形式にする
]

# EOF OA24o1o0g4o0

Step [OA24o1o0g5o0] Webソケット用総合ルート編集 - asgi.py ファイル

👇 以下の既存のファイルを編集してほしい

    └── 📂 src1
        ├── 📂 apps1
        │   └── 📂 tic_tac_toe_vol3o0               # アプリケーション
        │       └── 📂 websocks
        │           └── 📂 consumer_custom
        │               └── 📄 ver1o0.py
        └── 📂 project1                         # プロジェクト
👉          ├── 📄 asgi.py
            └── 📄 ws_urls_tic_tac_toe_v3.py    # Three
# ...略...


# * 以下を追加
# OA24o1o0g5o0 〇×ゲーム v3
from . import ws_urls_tic_tac_toe_v3
#                                  ^three
#    -        ----------------------
#    1        2
# 1. 同じディレクトリー
# 2. `src1/projectN/ws_urls_tic_tac_toe_v3.py`
#                   ----------------------


# ...略...
# この辺に os.environ.setdefault(...)


# ...略...


# この辺に以下のような文
# > 複数のアプリケーションの websocket_urlpatterns をマージします
# > websocket_urlpatterns_merged = []


# ...略...


# * 以下を追加
# OA24o1o0g5o0 〇×ゲーム v3
websocket_urlpatterns_merged.extend(
    ws_urls_tic_tac_toe_v3.websocket_urlpatterns)
#                        ^three

Step [OA24o1o0g6o0] 対局申込ビュー作成 - match_application/ver3o0 フォルダー

👇 以下のファイルを新規作成してほしい

    └── 📂 src1
        ├── 📂 apps1
        │   └── 📂 tic_tac_toe_vol3o0                   # アプリケーション Three
        │       ├── 📂 views
        │       │   └── 📂 match_application
        │       │       └── 📂 ver3o0
👉      │       │           └── 📄 __init__.py
        │       └── 📂 websocks
        │           └── 📂 consumer_custom
        │               └── 📄 ver1o0.py
        └── 📂 project1                             # プロジェクト
            ├── 📄 asgi.py
            └── 📄 ws_urls_tic_tac_toe_v3.py        # Three
# BOF [OA24o1o0g6o0]

# 〇×ゲーム2.0巻 対局申込1.0版
from apps1.tic_tac_toe_vol2o0.views.gui.match_application.ver1o0 import MatchApplicationView as ViewOfMatchApplicationV2g1o0
#                         ^two
#          ------------------                             ------        --------------------    ----------------------------
#          11                                             12            2                       3
#    -----------------------------------------------------------
#    10
# 10. `src1/apps1/tic_tac_toe_vol2o0/views/gui/match_application/ver1o0/__init__.py`
#           -----------------------------------------------------------
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `1.` の __init__.py ファイルに含まれるクラス
# 3. '2.' の別名

# 〇×ゲーム3.0巻 対局申込1.0版
from apps1.tic_tac_toe_vol3o0.views.match_application.ver1o0 import MatchApplicationView as ViewOfMatchApplicationV3g1o0
#                         ^three                         ^one
#          ------------------                         ------        --------------------    ----------------------------
#          11                                         12            2                       3
#    -------------------------------------------------------
#    10
# 10. `src1/apps1/tic_tac_toe_vol3o0/views/match_application/v1o0/__init__.py`
#           -----------------------------------------------------
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれる __init__.py ファイルにさらに含まれるクラス
# 3. '2.' の別名


class MatchApplicationView():
    """[OA24o1o0g6o0] 対局申込ビュー"""

    # 〇×ゲーム3.0巻 対局中3.0版
    playing_web_path = "/tic-tac-toe/vol3.0/playing/ver3.0/{0}/?&myturn={1}"
    #                                   ^three
    #                   ---------------------------------------------------
    #                   1
    # 1. `http://example.com:8000/tic-tac-toe/vol3.0/playing/ver3.0/Elephant/?&myturn=X`
    #                            ------------------------------------------------------

    @staticmethod
    def render(request):
        """描画"""

        # 以下のファイルは既存です
        from apps1.tic_tac_toe_vol2o0.views.gui.match_application.ver1o0.v_render import render_match_application
        #                         ^two
        #    --------------------------------------------------------------------        ------------------------
        #    1                                                                           2
        # 1. `src1/apps1/tic_tac_toe_vol2o0/views/gui/match_application/ver1o0/v_render.py`
        #          --------------------------------------------------------------------
        # 2. `1.` に含まれる関数

        return render_match_application(
            request,
            MatchApplicationView.playing_web_path,
            ViewOfMatchApplicationV2g1o0.template_path,
            ViewOfMatchApplicationV3g1o0.on_sent,
            ViewOfMatchApplicationV2g1o0.open)

# EOF [OA24o1o0g6o0]

Step [OA24o1o0g7o0] 対局申込ビュー作成 - playing/ver3o0 フォルダー

👇 以下のファイルを新規作成してほしい

    └── 📂 src1
        ├── 📂 apps1
        │   └── 📂 tic_tac_toe_vol3o0                   # アプリケーション Three
        │       ├── 📂 views
        │       │   ├── 📂 match_application
        │       │   │   └── 📂 ver3o0
        │       │   │       └── 📄 __init__.py
        │       │   └── 📂 playing
        │       │       └── 📂 ver3o0
👉      │       │           └── 📄 __init__.py
        │       └── 📂 websocks
        │           └── 📂 consumer_custom
        │               └── 📄 ver1o0.py
        └── 📂 project1                             # プロジェクト
            ├── 📄 asgi.py
            └── 📄 ws_urls_tic_tac_toe_v3.py        # Three
# BOF [OA24o1o0g7o0]

# 〇×ゲーム2.0巻 対局中1.0版
from apps1.tic_tac_toe_vol2o0.views.gui.playing.ver1o0 import PlayingView as ViewOfPlayingV2g1o0
#                         ^two
#          ------------------                   ------        -----------    -------------------
#          11                                   12            2              3
#    -------------------------------------------------
#    10
# 10. `src1/apps1/tic_tac_toe_vol2o0/views/gui/playing/ver1o0/__init__.py`
#           -------------------------------------------------
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれる `__init__.py` ファイルにさらに含まれるクラス
# 3. `2.` の別名

# 〇×ゲーム3.0巻 対局中1.0版
from apps1.tic_tac_toe_vol3o0.views.playing.ver1o0 import PlayingView as ViewOfPlayingV3g1o0
#                         ^three
#          ------------------               ------        -----------    -------------------
#          11                               12            2              3
#    ---------------------------------------------
#    10
# 10. `src1/apps1/tic_tac_toe_vol3o0/views/playing/ver1o0/__init__.py`
#           ---------------------------------------------
# 10, 12. ディレクトリー
# 11. アプリケーション
# 2. `12.` に含まれる `__init__.py` ファイルにさらに含まれるクラス
# 3. `2.` の別名


class PlayingView():
    """[OA24o1o0g7o0] 対局中ビュー"""

    web_socket_path = "/tic-tac-toe/v3.3/playing/"
    #                                ^three
    #                  --------------------------
    #                  1
    # 1. `ws://example.com/tic-tac-toe/v3.3/playing/Elephant/`
    #                     --------------------------

    @staticmethod
    def render(request, kw_room_name):
        """描画"""

        # 以下のファイルは既存です
        from apps1.tic_tac_toe_vol2o0.views.gui.playing.ver1o0.v_render import render_playing
        #                         ^two
        #    ----------------------------------------------------------        --------------
        #    1                                                                 2
        # 1. `src1/apps1/tic_tac_toe_vol2o0/views/gui/playing/ver1o0/v_render.py`
        #          ----------------------------------------------------------
        # 2. `1.` のファイルに含まれる render_playing 関数

        return render_playing(
            request,
            kw_room_name,
            PlayingView.web_socket_path,
            ViewOfPlayingV3g1o0.template_path,
            ViewOfPlayingV3g1o0.on_update,
            ViewOfPlayingV2g1o0.expected_pieces)

# EOF [OA24o1o0g7o0]

Step [OA24o1o0g8o0]

Marged to OA24o1o0g8o1o0

Step [OA24o1o0g8o1o0] ルート編集 - urls.csv ファイル

👇 以下の既存ファイルの末尾に追記してほしい

    ├── 📂 src1
    │   ├── 📂 apps1
    │   │   └── 📂 tic_tac_toe_vol3o0                   # アプリケーション Three
    │   │       ├── 📂 views
    │   │       │   └── 📂 o3o0                     # Three
    │   │       │       ├── 📂 match_application
    │   │       │       │   └── 📄 __init__.py
    │   │       │       └── 📂 playing
    │   │       │           └── 📄 __init__.py
    │   │       └── 📂 websocks
    │   │           └── 📂 consumer_custom
    │   │               └── 📄 ver1o0.py
    │   └── 📂 project1                             # プロジェクト
    │       ├── 📄 asgi.py
    │       └── 📄 ws_urls_tic_tac_toe_v3.py        # Three
    └── 📂 src1_meta
        └── 📂 data
👉          └── 📄 urls.csv
...略... file,path,name,comment,module,class,alias,method
...略...


../src1/project1/urls_tic_tac_toe_vol3o0_autogen.py,tic-tac-toe/vol3.0/match-application/ver3.0/,,"OA24o1o0g8o1o0 〇×ゲーム3.0巻 対局申込中3.0版",apps1.tic_tac_toe_vol3o0.views.match_application.ver3o0,MatchApplicationView,TicTacToe3o0MatchApplicationView3o0,render
../src1/project1/urls_tic_tac_toe_vol3o0_autogen.py,tic-tac-toe/vol3.0/playing/ver3.0/<str:kw_room_name>/,,"OA24o1o0g8o1o0 〇×ゲーム3.0巻 対局中3.0版",apps1.tic_tac_toe_vol3o0.views.playing.ver3o0,PlayingView,TicTacToe3o0PlayingView3o0,render

Step [OA24o1o0g8o2o0] ルート編集 - コマンド打鍵

👇 以下のコマンドを打鍵してほしい

cd ../src1_meta
python -m scripts.auto_generators.urls
cd ../src1
docker-compose restart
  • ディレクトリーは、がんばって移動してほしい
  • スクリプトについて See also: O3o2o_1o0g2o0
  • 設定ファイルを変更したら、サーバーの再起動が必要

テスト手順

Step [OA24o1o0g9o0] Web画面へアクセス

  • このゲームは2人用なので、Webページを2窓で開き、片方が X プレイヤー、もう片方が O プレイヤーとして遊んでください
  • テスト用のアカウント test1 は、もう作ってあるものとします
  • 最初のテストは 既存でない部屋名で、次のテストは 既存の部屋名 で行うといいかもしれません

👇 (既にログインしているかもしれないので)ログアウトを試す

📖 http://localhost:8000/accounts/vol1.0/logout/

👇 以下の URL を開いて、 test1 ユーザーでアクセスしてほしい

ユーザー名: test1
E-mail: (あなたに届く、あなたの2個目のEメールアドレス)
パスワード: test1example
パスワード(再入力) test1example

📖 http://localhost:8000/accounts/vol1.0/login/

👇 そして 以下の URL を開いて、 TestOA24o1o0g9o0 部屋に X 番として入ってほしい

📖 http://localhost:8000/tic-tac-toe/vol3.0/match-application/ver3.0/

ここで、ログアウトしたなら対局部屋を追い出されるべきだが、まだそこまで作っていない。

👇 それをいいことに、対局部屋のブラウザ画面を残したまま 今のユーザーをログアウトしてほしい

📖 http://localhost:8000/accounts/vol1.0/logout/

👇 以下の URL を開いて、スーパーユーザー でログインしなおしてほしい(既に作っているはずだ)

📖 http://localhost:8000/accounts/vol1.0/login/

👇 そして 以下の URL を開いて、 TestOA24o1o0g9o0 部屋に O 番として入ってほしい

📖 http://localhost:8000/tic-tac-toe/vol3.0/match-application/ver3.0/

👇 部屋、ユーザーを確認するには、管理画面を使うのが確実だ。
スーパーユーザーのまま、 以下の URL を開いて、管理画面に入っていてほしい

📖 http://localhost:8000/admin

サイドメニューから、 Rooms モデルを開いてほしい
TestOA24o1o0g9o0 room があるはずなので、開いてほしい

部屋に入っているユーザーの主キーが記録されていることを確認してほしい

例:

部屋名: TestOA24o1o0g9o0
対局者_先手Id: 2
対局者_後手Id: 1
盤面:
棋譜:

以下、3手ほど ○×ゲームを進めてほしい。
そのあと、もう一度 サイドメニューから Rooms モデルの中の TestOA24o1o0g9o0 room を開いてほしい。
盤面と、棋譜にテキストが入っていれば OK だ

例:

部屋名: TestOA24o1o0g9o0
対局者_先手Id: 2
対局者_後手Id: 1
盤面: .XX.....O
棋譜: 281

後処理

Step [OA24o1o0gA10o0] ランチャーのリンク用データ追加 - finished-lessons.csv ファイル

👇 以下の既存ファイルの最終行に追記してほしい

    └── 📂 src1
        ├── 📂 apps1
        │   ├── 📂 portal_v1                        # アプリケーション
        │   │   └── 📂 data
👉      │   │       └── 📄 finished-lessons.csv
        │   └── 📂 tic_tac_toe_vol3o0                   # アプリケーション Three
        │       ├── 📂 views
        │       │   └── 📂 o3o0                     # Three
        │       │       ├── 📂 match_application
        │       │       │   └── 📄 __init__.py
        │       │       └── 📂 playing
        │       │           └── 📄 __init__.py
        │       └── 📂 websocks
        │           └── 📂 consumer_custom
        │               └── 📄 ver1o0.py
        └── 📂 project1                             # プロジェクト
            ├── 📄 asgi.py
            ├── 📄 urls_practice.py
            └── 📄 ws_urls_tic_tac_toe_v3.py        # Three

👇 冗長なスペース,冗長なダブルクォーテーション,末尾のカンマ は止めてほしい

/tic-tac-toe/vol3.0/match-application/ver3.0/,OA24o1o0gA10o0 〇×ゲーム3.0巻 対局申込中3.0版

👇 ランチャーにリンクが追加されていることを確認してほしい

📖 http://localhost:8000/

次の記事

📖 Djangoで観戦モードを作ろう!

参考にした記事

非同期処理,スレッド関連

📖 Django: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async
📖 Asynchronous support
📖 How to correct " 'coroutine' object has no attribute 'data'" Error when using Telethon for Telegram?
📖 python3 の async/awaitを理解する
📖 Getting values from functions that run as asyncio tasks

文字列関連

📖 Python で文字列の一文字だけを変換

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?