Django:ファイルシステムos.pathをpathlibで置き換える場合どう書くか
Django:ファイルシステムos.pathをpathlibで置き換える場合どう書くか
os.pathとpathlibの書き方の違いをまとめます。
この記事のきっかけ
今現状Djangoについてわからないことを調べようとすると多くのサイトでファイルパスにos.pathを使っています。
pathlibはDjango3.4以降にできたらしいのでしょうがないのですが、Django初心者の私は何も考えずにこういった参考記事のScriptを真似してしまいます。
で、結果として500番エラーが発生し「なんでだろう」と調べることになりました。
import os
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
ちょっと別のことやると忘れて同じ間違いを繰り返すしてしまったので戒めを込めて備忘録です。
os.pathとpathlibは共にファイルパスシステム
色々調べると、2つのファイルシステムは共存することもできるようです。
私の環境ではなぜか「個別で動いても共存させると500エラー」という状況で共存できていません。
なので、基本的に『どちらかを選択して統一する』方向で構築していこうと思います。
ちなみに、今回は多言語化を考えこちらのサイトを参考にさせて頂いたところ500エラーに遭遇し記事にしました。
そもそも使っていたファイルシステム
作成していたサイトのsettings.pyはこんな感じです。
#settings.py from pathlib import Path from django.contrib.messages import constants as messages # Build paths inside the project like this: os.path.join(BASE_DIR, ...) #BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = Path(__file__).resolve().parent.parent (以下略)
ファイルシステムはpathlib。import osは記載されていません。
ここに[ import os ]を書き加えてロードしたところ『internalServerError』が発生しました。う~ん、なぜ?
os.pathが使えないならpathlibで書き換えてやればいい
両方ともファイルシステムなわけですからね。変換できるだろうと。
やりたいことは多言語化なので、その際にsettings.pyに追加するパーツを抜き出してみます。
■通常の言語を設定
LANGUAGE_CODE = 'ja'
■ミドルウェアを追加
MIDDLEWARE = [
(中略)
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',#この位置に追加
'django.middleware.common.CommonMiddleware',
(中略)
]
■localeフォルダへのパスを作成
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
今回発生したエラーはファイルシステムが原因なので、os.path を利用している3番目のパーツが問題です。
だったら、このパスをpathlibで書き換えちゃえば問題解決って事です。
os.path.join(BASE_DIR,'locale')を【pathlib】で書き換える
この場合、BASE_DIR\localeというディレクトリを指示していることになる様です。
同じpathを作るためには[ BASE_DIR / 'locale' ]という表現で出来てしまうらしい...なんて簡単な...。
難しく書こうとすればこんな表現もできる様子。というかこちらが正道?
#簡単な表記方法
BASE_DIR / 'locale'
#王道な記載方法
BASE_DIR.joinpath('locale')
他にもos.pathの表記をpathlibに置き換えてみる
親ディレクトリ
# os os.path.dirname(os.path.abspath(__file__)) # pathlib pathlib.Path(__file__).resolve().parent
BASE_DIR ※settings.pyに記載するやつ
#os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #pathlib BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_ROOT ※settings.pyに記載するやつ
#os PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) #pathlib PROJECT_ROOT = Path(__file__).resolve().parent
pathの合成 ※foo/bar/baz を作成
# os os.path.join("foo", os.path.join("bar", "baz")) # pathlib pathlib.Path("foo") / "bar" / "baz"
カレントディレクトリ取得
#os current = os.getcwd() #pathlib current = Path()
ちなみに、pathlib にカレントディレクトリを変更するコマンドは無いらしい。でも動作は絶対パスで送れば良い訳で、それほど問題は無いような気がします。
ファイルの存在確認
#os
os.path.exists('temp/new_file.txt')
#pathlib
p_new_file = pathlib.Path('temp/new_file.txt')
p_new_file.exists()
存在すればTRUE、なければFALSEが返ります。
pthlibで使っているresolve()って何?
調べたらこんな情報にひきあたりました。
- resolve:絶対パスを作成する※相対パスを絶対パスに変換する
- absolute:絶対パスを取得する
なるほど。BASE_DIRの記載などは「絶対パスを作成するよ」と宣言して、settings.pyのある場所から親.親と渡ったんですね。
settings.py内で記載するLocaleディレクトリへのパス記載方法
こうやってまとめてみるといろんな記載方法で表現できるとわかります。
└─my_site
├─locale
└─settings.py
settings.pyの所在地は【プロジェクト\プロジェクト\settings.py】なので、表現方法としてはこんな感じです。
- カレントディレクトリの中にあるlocaleディレクトリ
Path('locale') - PROJECT_ROOT内のlocaleディレクトリ
PROJECT_ROOT.joinpath('locale') - BASE_DIR\プロジェクトディレクトリ内のlocaleディレクトリ
BASE_DIR.joinpath('my_site','locale')
ちなみに、BASE_DIR/PROJECT_ROOTとは次の場所を示します。
- BASE_DIR:manage.pyが存在する場所
- PROJECT_ROOT:settings.pyが存在する場所
settings.pyの場所=PROJECT_ROOTなので、Path('locale')とPROJECT_ROOT.joinpath('locale')が同じ場所を意味する事になります。
まとめ
う~ん、os.pathはなぜ動かなかったんだろう。
おかげでファイルシステムについて深堀する切っ掛けを頂いた訳だけど、共存構築出来た方がコピペには楽だよなぁと思いました。


