LoginSignup
0
0

More than 1 year has passed since last update.

DjangoとDocker練習o3o2o_1o0 URL設定を自動化しよう!

Last updated at Posted at 2022-08-21

サンプルを見る

📖 この記事のゴール

目標

URLの設定はめんどうだ。自動化しよう

情報

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

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

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

What is This is
OS Windows10
Container Docker
Editor Visual Studio Code (以下 VSCode と表記)

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

    ├── 📂 src1
    │   ├── 📂 apps1
    │   │   └── 📂 practice_vol1o0              # アプリケーション名
    │   │       ├── 📂 templates
    │   │       │   └── 📂 practice_vol1o0
    │   │       │       └── 📂 hello
    │   │       │           └── 📄 ver1o0.html
    │   │       └── 📂 views
    │   │           └── 📂 hello
    │   │               └── 📂 ver1o0
    │   │                   └── 📄 __init__.py
    │   ├── 📂 data
    │   ├── 📂 project1                  # プロジェクト名
    │   │   ├── 📄 __init__.py
    │   │   ├── 📄 asgi.py
    │   │   ├── 📄 settings_secrets.py
    │   │   ├── 📄 settings.py
    │   │   ├── 📄 urls_practice.py
    │   │   ├── 📄 urls.py
    │   │   └── 📄 wsgi.py
    │   ├── 📂 project2
    │   ├── 🐳 docker-compose-project2.yml
    │   ├── 🐳 docker-compose.yml
    │   ├── 🐳 Dockerfile
    │   ├── 📄 manage.py
    │   └── 📄 requirements.txt
    └── 📄 .gitignore

実装手順

Step. Dockerコンテナの起動

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

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

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

Step [O3o2o_1o0g1o0] データ作成 - src1_meta/data/urls.csv ファイル

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

    ├── 📂 src1     # 既存
    └── 📂 src1_meta
        └── 📂 data
👉          └── 📄 urls.csv
file,path,name,comment,module,class,alias,method
../src1/project1/urls_autogen.py,,,"集約ファイル",,,,
../src1/project1/urls_practice_vol1o0_autogen.py,practice/vol1.0/hello-alias/ver1.0/,practice_vol1o0_hello_alias,"O3o2o_1o0g1o0 練習1.0巻 こんにちわ別名1.0版",apps1.practice_vol1o0.views.hello.ver1o0,HelloView,,render

Step [O3o2o_1o0g2o_1o0] Pythonパッケージインストール - pandas

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

pip install pandas

Step [O3o2o_1o0g2o_1o0] スクリプト作成 - init.py ファイル

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

    ├── 📂 src1     # 既存
    └── 📂 src1_meta
        ├── 📂 data
        │   └── 📄 urls.csv
        └── 📂 scripts
            └── 📂 auto_generators
                └── 📂 urls
👉                  └── 📄 __init__.py

👇 中身は空っぽでよい

Step [O3o2o_1o0g2o_2o0] スクリプト作成 - file_path.py ファイル

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

    ├── 📂 src1     # 既存
    └── 📂 src1_meta
        ├── 📂 data
        │   └── 📄 urls.csv
        └── 📂 scripts
            └── 📂 auto_generators
                └── 📂 urls
                    ├── 📄 __init__.py
👉                  └── 📄 file_path.py
# BOF [O3o2o_1o0g2o_2o0]

import os


class FilePath:
    """ファイルパス

    Examples
    --------
    C:\this\is\a\base.name
                 ---]-----
                 111 112
                 ---------
                 11
    ----------------------
    10

    10. file path
    11. basename
    111. stem
    112. extension with dot
    """

    @staticmethod
    def create_or_err(file_path):
        # ファイル名オブジェクト
        file_path_o = FilePath(file_path)

        if file_path_o.is_valid():
            return file_path_o, None

        return None, file_path_o._last_err

    def __init__(self, value):
        # 値
        self._value = value
        # 最後のエラーメッセージ
        self._last_err = None
        # ベースネーム
        self._basename = None
        # ステム
        self._stem = None

    @property
    def value(self):
        """"""
        return self._value

    @property
    def last_err(self):
        """最後のエラーメッセージ"""
        return self._last_err

    @property
    def basename(self):
        """ベースネーム"""
        if self._basename is None:
            self._basename = os.path.basename(self.value)

        return self._basename

    @property
    def stem(self):
        """ステム"""
        if self._stem is None:
            # 拡張子を除去
            self._stem = self.basename[:-3]

        return self._stem

    def is_valid(self):
        """ファイル名が `urls_*_autogen.py` な感じかチェックします"""

        basename = os.path.basename(self._value)

        if basename.startswith("urls_") and basename.endswith("_autogen.py"):
            return True

        self._last_err = f"書き出すファイル名の先頭は `urls_`、 末尾は `_autogen.py` にしてください。 basename:{basename}"
        return False

# EOF [O3o2o_1o0g2o_2o0]

Step [O3o2o_1o0g2o_3o0] スクリプト作成/テスト作成 - file_path.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
    │               └── 📄 file_path.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
👉                      └── 📄 file_path.py
# BOF [O3o2o_1o0g2o_3o0]

"""テスト
# cd {testsのあるディレクトリー}

python -m tests.src1_meta.scripts.auto_generators.urls.file_path
"""
from src1_meta.scripts.auto_generators.urls.file_path import FilePath


def test_ok1():
    # 出力先ファイルパスオブジェクト
    file_path_o, err = FilePath.create_or_err(
        'C:\\this\\is\\a\\urls_path_autogen.py')
    if not err is None:
        print(f"F\n{err}")
        return

    print(".", end="")  # Succeed


def test_not_starts_with_urls():
    # 出力先ファイルパスオブジェクト
    file_path_o, err = FilePath.create_or_err(
        'C:\\this\\is\\a\\path_autogen.py')
    if err == "書き出すファイル名の先頭は `urls_`、 末尾は `_autogen.py` にしてください。 basename:path_autogen.py":
        print(".", end="")
        return

    print("F")  # Failed


def test_not_ends_with_autogen():
    # 出力先ファイルパスオブジェクト
    file_path_o, err = FilePath.create_or_err(
        'C:\\this\\is\\a\\urls_path.py')
    if err == "書き出すファイル名の先頭は `urls_`、 末尾は `_autogen.py` にしてください。 basename:urls_path.py":
        print(".", end="")
        return

    print("F", end="")


if __name__ == '__main__':
    test_ok1()
    test_not_starts_with_urls()
    test_not_ends_with_autogen()

# EOF [O3o2o_1o0g2o_3o0]

Step [O3o2o_1o0g2o_4o0] スクリプト作成/テスト実行 - file_path.py ファイル

👇 以下のディレクトリーから、コマンドを打鍵してほしい

👉  📂
    ├── 📂 src1
    ├── 📂 src1_meta
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        └── 📄 file_path.py

Input:

# cd {testsのあるディレクトリー}

python -m tests.src1_meta.scripts.auto_generators.urls.file_path

Output:

...

👆 エラーが表示されていなければオーケーだ

Step [O3o2o_1o0g2o_4o1o0] スクリプト作成 - path_renderer.py ファイル

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

    ├── 📂 src1
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
    │               ├── 📄 file_path.py
👉  │               └── 📄 path_renderer.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        └── 📄 file_path.py
# BOF [O3o2o_1o0g2o_4o1o0]

import pandas as pd


class PathRenderer:
    def __init__(self):
        self._module = ""
        self._real_class_name = ""
        self._alias_class_name = pd.NA
        self._method = ""
        self._comment = pd.NA
        self._path = pd.NA
        self._name = pd.NA

    @property
    def module(self):
        """モジュール"""
        return self._module

    @module.setter
    def module(self, value):
        self._module = value

    @property
    def real_class_name(self):
        """実クラス名"""
        return self._real_class_name

    @real_class_name.setter
    def real_class_name(self, value):
        self._real_class_name = value

    @property
    def alias_class_name(self):
        """クラスの別名"""
        return self._alias_class_name

    @alias_class_name.setter
    def alias_class_name(self, value):
        self._alias_class_name = value

    @property
    def virtual_class_name(self):
        """実際的なクラス名"""
        if pd.isnull(self.alias_class_name):
            return self.real_class_name
        else:
            return self.alias_class_name

    @property
    def method(self):
        """メソッド"""
        return self._method

    @method.setter
    def method(self, value):
        self._method = value

    @property
    def comment(self):
        """コメント"""
        return self._comment

    @comment.setter
    def comment(self, value):
        self._comment = value

    @property
    def path(self):
        """パス"""
        return self._path

    @path.setter
    def path(self, value):
        if pd.isnull(value):
            # 空文字列の指定があり得ます。
            # pandas は空文字列と NaN を区別せず NaN にするので、空文字列に変換します
            self._path = ""
            return

        self._path = value

    @property
    def name(self):
        """名前"""
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    def create_header_text(self):
        return f"from {self.module} import {self.real_class_name}{self._create_alias_class_name_phrase()}\n"

    def _create_alias_class_name_phrase(self):
        if pd.isnull(self.alias_class_name):
            return ""
        else:
            return f" as {self.alias_class_name}"

    def create_urlpatterns_item_text(self):
        # コメント
        comment_phrase = self._create_comment_phrase()
        # name引数
        name_arg = self._create_name_arg()

        return f"""{comment_phrase}
    path('{self.path}', {self.virtual_class_name}.{self.method}{name_arg}),
"""

    def _create_comment_phrase(self):
        """コメント句"""
        if pd.isnull(self._comment):
            # 省略可
            return ""
        else:
            return f"""
    # {self._comment}"""

    def _create_name_arg(self):
        """名前引数"""
        if pd.isnull(self.name):
            # 省略可
            return ""
        else:
            return f", name='{self.name}'"

# EOF [O3o2o_1o0g2o_4o1o0]

Step [O3o2o_1o0g2o_4o1o1o0] スクリプト作成/テスト作成 - path_renderer.py ファイル

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

    ├── 📂 src1
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
    │               ├── 📄 file_path.py
    │               └── 📄 path_renderer.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        ├── 📄 file_path.py
👉                      └── 📄 path_renderer.py
# BOF [O3o2o_1o0g2o_4o1o1o0]

"""テスト
# cd {testsのあるディレクトリー}

python -m tests.src1_meta.scripts.auto_generators.urls.path_renderer
"""
from src1_meta.scripts.auto_generators.urls.path_renderer import PathRenderer


def test_ok1():
    # Test data
    path_rdr = PathRenderer()
    path_rdr.method = "render"
    path_rdr.module = "src1.this.is.a.file"
    path_rdr.real_class_name = "HelloClass"
    path_rdr.alias_class_name = "GoodMorningClass"
    path_rdr.comment = "This is a text."
    path_rdr.path = "C:\\This\\Is\\A\\Path\\urls_example_autogen.py"
    path_rdr.name = "home"

    actual = path_rdr.create_header_text()
    expected = """from src1.this.is.a.file import HelloClass as GoodMorningClass
"""

    if not actual == expected:
        print(
            f"F\nimport_statement failed. actual:[{actual}] expected:[{expected}]\n")
        return

    actual = path_rdr.create_urlpatterns_item_text()
    expected = """
    # This is a text.
    path('C:\\This\\Is\\A\\Path\\urls_example_autogen.py', GoodMorningClass.render, name='home'),
"""

    print(".", end="")  # Succeed

    if not actual == expected:
        print(
            f"F\nurlpatterns_item_text failed. actual:[{actual}] expected:[{expected}]\n")
        return

    print(".", end="")


if __name__ == '__main__':
    test_ok1()

# EOF [O3o2o_1o0g2o_4o1o1o0]

Step [O3o2o_1o0g2o_4o1o2o0] スクリプト作成/テスト実行 - path_renderer.py ファイル

👇 以下のディレクトリーから、コマンドを打鍵してほしい

👉  📂
    ├── 📂 src1
    ├── 📂 src1_meta
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        └── 📄 path_renderer.py

Input:

# cd {testsのあるディレクトリー}

python -m tests.src1_meta.scripts.auto_generators.urls.path_renderer

Output:

..

👆 エラーが表示されていなければオーケーだ

Step [O3o2o_1o0g2o_4o2o0] スクリプト作成 - urls_file_render.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
    │               ├── 📄 file_path.py
    │               ├── 📄 path_renderer.py
👉  │               └── 📄 urls_file_render.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        ├── 📄 file_path.py
                        └── 📄 path_renderer.py
# BOF [O3o2o_1o0g2o_4o2o0]

class UrlsFileRender:
    def __init__(self):
        self._path_render_list = []

    @property
    def path_render_list(self):
        return self._path_render_list

    def create_file_text(self):
        return f'''# AutoGenBegin [O3o2o_1o0g4o0]

from django.urls import path

{self._create_import_paragraphs()}

urlpatterns = [{self.create_path_items()}]

# AutoGenEnd [O3o2o_1o0g4o0]
'''

    def _create_import_paragraphs(self):
        s = ""
        for path_rdr in self._path_render_list:
            s += path_rdr.create_header_text()
        return s

    def create_path_items(self):
        s = ""
        for path_rdr in self._path_render_list:
            s += path_rdr.create_urlpatterns_item_text()
        return s

# EOF [O3o2o_1o0g2o_4o2o0]

Step [O3o2o_1o0g2o_4o3o0] スクリプト作成 - urls_summary_render.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
    │               ├── 📄 file_path.py
    │               ├── 📄 path_renderer.py
    │               ├── 📄 urls_file_render.py
👉  │               └── 📄 urls_summary_render.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        ├── 📄 file_path.py
                        └── 📄 path_renderer.py
# BOF [O3o2o_1o0g2o_4o3o0]

from pathlib import Path


class UrlsSummaryRender:

    @staticmethod
    def create_header_text():
        return """# AutoGenBegin [O3o2o_1o0g4o0]

from django.urls import include, path

# [O3o1o0gA11o0] 総合ルート編集
from .settings import PROJECT_NAME
#    ]--------        ------------
#    12               3
# 1. 同じディレクトリー
# 2. `src1/projectN/settings.py`
#                   --------
# 3. 変数


urlpatterns = [
"""

    @staticmethod
    def create_footer_text():
        return """]

# AutoGenEnd [O3o2o_1o0g4o0]
"""

    def __init__(self):
        self._file_stems = set()
        self._file_path = None

    @property
    def file_path(self):
        return self._file_path

    @file_path.setter
    def file_path(self, value):
        self._file_path = value

    @property
    def parent_directory(self):
        print(
            f"[UrlsSummaryRender parent_directory] self._file_path:{self._file_path}")
        return Path(self._file_path).parent.absolute()

    def add_stem(self, stem):
        self._file_stems.add(stem)

    def create_file_text(self):
        s = UrlsSummaryRender.create_header_text()
        s += self.create_path_items_text()
        s += UrlsSummaryRender.create_footer_text()
        return s

    def create_path_items_text(self):
        # 辞書順ソート
        file_stems = list(self._file_stems)
        file_stems.sort()

        s = ""
        # 各ファイル
        for stem in file_stems:
            s += f"""    path('', include(f'{{PROJECT_NAME}}.{stem}')),
"""
        return s

# EOF [O3o2o_1o0g2o_4o3o0]

Step [O3o2o_1o0g2o_4o4o0] スクリプト作成 - file_collection.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
👉  │               ├── 📄 file_collection.py
    │               ├── 📄 file_path.py
    │               ├── 📄 path_renderer.py
    │               ├── 📄 urls_file_render.py
    │               └── 📄 urls_summary_render.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        ├── 📄 file_path.py
                        └── 📄 path_renderer.py
# BOF [O3o2o_1o0g2o_4o4o0]

import glob
from pathlib import Path


class FileCollection:

    @staticmethod
    def find_to(path_pattern):

        # 名前がマッチしているファイルを探す
        # print(f"[FileCollection find_to] path_pattern:{path_pattern}")
        target_path_objects = glob.glob(path_pattern)
        print(
            f"[DirectFileCollectionory find_to] len(target_path_objects):{len(target_path_objects)}")

        # 文字列のリストに変換
        target_path_str_list = []

        for target_path_o in target_path_objects:
            # print(f"[FileCollection find_to] target_path_o:{target_path_o}")
            target_path_str_list.append(str(target_path_o))

        return FileCollection(target_path_str_list)

    def __init__(self, target_path_str_list):
        self._target_path_str_list = target_path_str_list

    @property
    def target_path_str_list(self):
        return self._target_path_str_list

    def remove_all(self, removee_file_str_list):
        for file_str in removee_file_str_list:
            s = str(Path(file_str).absolute().resolve())
            try:
                self._target_path_str_list.remove(s)
            except ValueError as e:
                print(f"[FileCollection remove_all] Remove failed. error:{e}")
                pass

# EOF [O3o2o_1o0g2o_4o4o0]

Step [O3o2o_1o0g2o0] スクリプト作成 - urls/init.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
👉  │               ├── 📄 __init__.py
    │               ├── 📄 file_path.py
    │               ├── 📄 path_renderer.py
    │               ├── 📄 urls_file_render.py
    │               └── 📄 urls_summary_render.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        └── 📄 file_path.py
# BOF [O3o2o_1o0g2o0]

import os
import pandas as pd
from pathlib import Path

# [O3o2o_1o0g2o_3o0]
from .file_path import FilePath
#    ]---------        --------
#    12                3
# 1. 同じディレクトリー
# 2. file_path.py
#    ---------
# 3. クラス名

# [O3o2o_1o0g2o_4o1o0]
from .path_renderer import PathRenderer

# [O3o2o_1o0g2o_4o2o0]
from .urls_file_render import UrlsFileRender

# [O3o2o_1o0g2o_4o3o0]
from .urls_summary_render import UrlsSummaryRender

# [O3o2o_1o0g2o_4o4o0]
from .file_collection import FileCollection


class UrlsAutoGenerator:
    def __init__(self):
        self._summary_file_to_export = None

    def execute(self):
        # CSV 読取
        df = pd.read_csv('data/urls.csv')
        #                 -------------
        #                 1
        # 1. `src1_meta/data/urls.csv` を読取
        #               -------------

        # print(df)
        """
        Examples
        --------
                                                       file                                path                         name  ...      class alias  method
        0                  ../src1/project1/urls_autogen.py                                 NaN                          NaN  ...        NaN   NaN     NaN
        1  ../src1/project1/urls_practice_vol1o0_autogen.py  practice/vo1o0/hello-alias/ver1o0/  practice_vol1o0_hello_alias  ...  HelloView   NaN  render
        """

        print(f"Current working directory:{os.getcwd()}")

        # URL設定ファイル自動生成
        urls_file_map = self.create_urls_file_map(df)

        # 集約ファイル自動生成
        urls_summary_render = self.create_url_summary_render(df)

        # 集約ファイルが置いてあるディレクトリー
        path1 = urls_summary_render.parent_directory
        # パスに "this/is/a/pen/../paper" が含まれていれば、 "this/is/a/paper" に解決する処理
        path1 = path1.resolve()
        # 検索対象
        file_collection = FileCollection.find_to(f"{path1}/urls_*_autogen.py")
        # 生成対象のファイルを除外
        file_collection.remove_all(urls_file_map.keys())
        # 残ったファイルは削除対象
        for file_path in file_collection.target_path_str_list:
            abs_path = str(Path(file_path).absolute().resolve())
            print(f"* [ ] Remove {abs_path}")

        # どんなファイルを書き出すかの一覧を出力
        for file_path, urls_file_o in urls_file_map.items():
            abs_path = str(Path(file_path).absolute().resolve())
            print(f"* [ ] Write {abs_path}")

        abs_path = str(Path(self._summary_file_to_export).absolute().resolve())
        print(f"* [ ] Write {abs_path}")
        print(f"Ok? (y/n)")
        key = input()

        if key.upper() == "Y":
            # ファイルの削除
            for file_path in file_collection.target_path_str_list:
                abs_path = str(Path(file_path).absolute().resolve())
                print(f"Remove... {abs_path}")
                os.remove(abs_path)

            # 各ファイル書出し
            for file_path, urls_file_o in urls_file_map.items():
                abs_path = str(Path(file_path).absolute().resolve())
                # ファイル書出し
                with open(abs_path, 'w', encoding="utf8") as f:
                    print(f"Write... {abs_path}")
                    f.write(urls_file_o.create_file_text())

            # ファイル書出し
            abs_path = str(
                Path(self._summary_file_to_export).absolute().resolve())
            with open(abs_path, 'w', encoding="utf8") as f:
                print(f"Write... {abs_path}")
                f.write(urls_summary_render.create_file_text())

    def create_urls_file_map(self, df):
        """URL設定ファイル自動生成"""

        # `urls_*_autogen.py` ファイル描画オブジェクト
        urls_file_map = {}

        # 各行
        df = df.reset_index()  # make sure indexes pair with number of rows
        for index, row in df.iterrows():

            # 出力先ファイルパスオブジェクト
            file_path_o, err = FilePath.create_or_err(row['file'])
            if not err is None:
                print(err)
                continue

            method_temp = row["method"]
            if pd.isnull(method_temp):
                # method列が空なら集約ファイルとします
                self._summary_file_to_export = file_path_o.value
                continue

            path_rdr = PathRenderer()
            path_rdr.method = method_temp
            path_rdr.module = row["module"]
            path_rdr.real_class_name = row["class"]
            path_rdr.alias_class_name = row['alias']
            path_rdr.comment = row["comment"]
            path_rdr.path = row["path"]
            path_rdr.name = row["name"]

            # urls_*_aurogen.py ファイル オブジェクト取得
            if not file_path_o.value in urls_file_map:
                urls_file_map[file_path_o.value] = UrlsFileRender()

            urls_file_o = urls_file_map[file_path_o.value]
            urls_file_o.path_render_list.append(path_rdr)

        return urls_file_map

    def create_url_summary_render(self, df):
        """集約ファイル自動生成"""

        urls_summary_render = UrlsSummaryRender()

        # Distinct
        df = df.reset_index()  # make sure indexes pair with number of rows
        for index, row in df.iterrows():
            # 出力先ファイル名オブジェクト
            file_path_o, err = FilePath.create_or_err(row['file'])
            if not err is None:
                print(err)
                continue

            method_temp = row["method"]
            if pd.isnull(method_temp):
                # Ignored. method列が空なら集約ファイル
                urls_summary_render.file_path = row["file"]
                continue

            # ステムをリストに追加
            urls_summary_render.add_stem(file_path_o.stem)

        return urls_summary_render

# EOF [O3o2o_1o0g2o0]

Step [O3o2o_1o0g2o1o0] スクリプト作成 - urls/main.py ファイル

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

    ├── 📂 src1     # 既存
    ├── 📂 src1_meta
    │   ├── 📂 data
    │   │   └── 📄 urls.csv
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📂 urls
    │               ├── 📄 __init__.py
👉  │               ├── 📄 __main__.py
    │               ├── 📄 file_path.py
    │               ├── 📄 path_renderer.py
    │               ├── 📄 urls_file_render.py
    │               └── 📄 urls_summary_render.py
    └── 📂 tests
        └── 📂 src1_meta
            └── 📂 scripts
                └── 📂 auto_generators
                    └── 📂 urls
                        └── 📄 file_path.py
# BOF [O3o2o_1o0g2o1o0]

from .__init__ import UrlsAutoGenerator


def main():
    urlsAutoGenerator = UrlsAutoGenerator()
    urlsAutoGenerator.execute()


if __name__ == "__main__":
    main()

# EOF [O3o2o_1o0g2o1o0]

テスト手順

Step [O3o2o_1o0g3o0] コマンド実行

👇 以下のディレクトリーから、コマンドを打鍵してほしい

    📂
    ├── 📂 src1
👉  ├── 📂 src1_meta
    │   └── 📂 scripts
    │       └── 📂 auto_generators
    │           └── 📄 urls.py
    └── 📂 tests
# ディレクトリーを移動してほしい
# cd src1_meta

# See also: [O3o2o_1o0g2o0]
python -m scripts.auto_generators.urls

Output:

Current working directory:C:\Users\むずでょ\Documents\GitHub\webgl-practice\me\src1_meta
[UrlsSummaryRender parent_directory] self._file_path:../src1/project1/urls_autogen.py
[DirectFileCollectionory find_to] len(target_path_objects):0
[FileCollection remove_all] Remove failed. error:list.remove(x): x not in list
* [ ] Write C:\Users\むずでょ\Documents\GitHub\django-practice2\src1\project1\urls_practice_vol1o0_autogen.py
* [ ] Write C:\Users\むずでょ\Documents\GitHub\django-practice2\src1\project1\urls_autogen.py
Ok? (y/n)

Input:

y

Output:

Write... C:\Users\むずでょ\Documents\GitHub\django-practice2\src1\project1\urls_warabenture_vol1o0_autogen.py
Write... C:\Users\むずでょ\Documents\GitHub\django-practice2\src1\project1\urls_autogen.py

Step [O3o2o_1o0g4o0] 確認

👇 以下のファイルが自動生成されていることを確認してほしい

    ├── 📂 src1
    │   └── 📂 project1
👉  │       ├── 📄 urls_autogen.py
👉  │       └── 📄 urls_practice_vol1o0_autogen.py
    └── 📂 src1_meta
        ├── 📂 data
        │   └── 📄 urls.csv
        └── 📂 scripts
            └── 📂 auto_generators
                └── 📄 urls.py

📄 urls_autogen.py:

# AutoGenBegin [O3o2o_1o0g4o0]

from django.urls import include, path

# [O3o1o0gA11o0] 総合ルート編集
from .settings import PROJECT_NAME
#    ]--------        ------------
#    12               3
# 1. 同じディレクトリー
# 2. `src1/projectN/settings.py`
#                   --------
# 3. 変数


urlpatterns = [
    path('', include(f'{PROJECT_NAME}.urls_practice_vol1o0_autogen')),
]

# AutoGenEnd [O3o2o_1o0g4o0]

📄 urls_practice_vol1o0_autogen.py

# AutoGenBegin [O3o2o_1o0g4o0]

from django.urls import path

from apps1.practice_vol1o0.views.hello.ver1o0 import HelloView


urlpatterns = [
    # [O3o2o_1o0g1o0] 練習1.0巻 こんにちわ別名1.0版
    path('practice/vol1.0/hello-alias/ver1.0/', HelloView.render, name='practice_vol1o0_hello_alias'),
]

# AutoGenEnd [O3o2o_1o0g4o0]

Step [O3o2o_1o0g5o0] 総合ルート編集 - urls.py

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

    ├── 📂 src1
    │   └── 📂 project1
    │       ├── 📄 urls_practice_vol1o0_autogen.py
👉  │       └── 📄 urls.py                   # こっち
    └── 📂 src1_meta
        ├── 📂 data
        │   └── 📄 urls.csv
        └── 📂 scripts
            └── 📂 auto_generators
                └── 📄 urls.py
# ...略...


# [O3o2o_1o0g5o0] 自動生成されたURL設定
from .urls_autogen import urlpatterns as urlpatterns_autogen
#    ]------------        -----------    -------------------
#    12                   3              4
# 1. 同じディレクトリー
# 2. `src1/projectN/urls_autogen.py`
#                   ------------
# 3. `2.` に含まれる変数
# 4. `3.` の別名


# ...略... urlpatterns = [
# ...略... ]


# [O3o2o_1o0g5o0] 自動生成されたURL設定
urlpatterns.extend(urlpatterns_autogen)

Step [O3o2o_1o0g6o0] Webページにアクセスする

📖 http://localhost:8000/practice/vol1.0/hello-alias/ver1.0/

トラブルシューティング

もし、 TemplateDoesNotExist at / といったエラーメッセージが出てきた場合、
同じURLを指す複数の path( ... ) が urlpatterns変数に設定されていることが考えられる。
がんばって重複しないようにしてほしい

次の記事

📖 DjangoのHTMLのボイラープレートを減らすテンプレートを使おう!

参考にした記事

Python

📖 Writing Unicode text to a text file?
📖 Usage of __main__.py in Python
📖 [Django] 自動テストについてのまとめ

Pandas

📖 pandas.isnull

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