サンプルを見る
📖 この記事のゴール
目標
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] 自動テストについてのまとめ