qtatsuの週報

初心者ですわぁ

Djangoのstartprojectをテンプレ化して繰り返し使おう

前書き

この記事は、JSL(日本システム技研) Advent Calendar 2020 - Qiita 12/9の記事です!

Djangoを使ったwebアプリケーション開発で、実装したことのない機能や初めて使うライブラリはサンプルアプリを作成して実際に動かしてみることが多いと思います。 しかしDjangoのプロジェクト立ち上げはそれなりに面倒です。startprojectコマンドを打ち、ディレクトリの切り方を変えてsettings.pyを書き換えて、gitignoreを書いて...など、繰り返し作業が多いです。

元々はコピペ実行可能なスクリプトを作って上記の作業をやっていたのですが、Djangoにはテンプレートという仕組みがあることを知りました。(HTMLのテンプレートとは無関係です!) プロジェクトの雛形を一度作っておけば、それをテンプレートとしてstartprojectを実行することができます。

githubのurlで直接テンプレートが入ったレポジトリをstartprojectコマンドに渡すこともできます。(ただし残念ながらmacosではgithub直指定は不可能<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] ...> · Issue #83 · arocks/edge · GitHub)

環境

バージョン
MacOS Catalina 10.15.6
Python3 3.8.6
Django 3.0.7

参考リンク

公式ドキュメント

django-admin and manage.py | Django documentation | Django

こちらの記事を参考にさせていただきました!

https://www.valentinog.com/blog/django-project/


今回は触れませんが、雛形を自動作成するツールもあります。 Welcome to Cookiecutter Django’s documentation! — Cookiecutter Django 2020.50.3 documentation

テンプレートの作成の基本手順

テンプレートプロジェクトの立ち上げ

まずは通常の手順でプロジェクトを作成します。これをテンプレート用のプロジェクトとして使います。

注: この記事の手順をそのまま進めるなら、「config」という名前にすることをおすすめします。後でコマンドの引数にこの名前で渡しています。

$ mkdir tmp-template-project
$ cd tmp-template-project/
$ python3 -m venv env
$ source env/bin/activate
$ pip install Django==3.0.7

# プロジェクト作成
$ django-admin startproject config .

プロジェクトの構成変更

適当にプロジェクトを変更しましょう。自分はsettingsディレクトリを作って、productionとdevelop用の設定ファイルを分けてみました。

$ mkdir config/settings
$ mv config/settings.py config/settings/develop.py
$ cp config/settings/develop.py config/settings/production.py

あとはファイルの中身も変更しておきましょうか。設定ファイルのタイムゾーンを編集しておきました。

TIME_ZONE = 'Asia/Tokyo'

cmsアプリも作っておきます。URLなどの設定をしておいてもいいと思います。

$ python manage.py startapp cms

あとはrequirements.txtによく使うライブラリを書いておくのも良いと思います。gitignoreも置いておくと便利かもしれないです。何度も同じようなものを使うなら、入れておきましょう。

プロジェクト名をプレースホルダーに変換

概要

Djangoのプロジェクトテンプレート機能の使用手順で「は?」と思うのはここだけです。

  • startprojectコマンドで命名したプロジェクト名(config)を、プレースホルダ{{ project_name}}に置き換えます。
  • これはプロジェクト配下全てのファイルについて行う必要があります。

例えば、./config/wsgi.pyには以下のようなコードがあります。

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

以下のように変更します。

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '{{ project_name }}.settings')

このようにする理由は、公式ドキュメントのstartprojectの項目をみると納得できます。->django-admin and manage.py | Django documentation | Django

project_name – the project name as passed to the command

「project_name」という変数で渡ってきた値を置換していくことができるため、プレースホルダーでこの辺数名を指定することができるというわけです。 詳しくは、後半の「その他のtemplate context を使ってみる」をよければ参照してください。

一撃で変換するスクリプト

文字列configを全ファイルから探して手動で書き換える...なんてことはありえないので、以下のように置換します。

なお、macos環境を想定しています。sedコマンドをLinux環境で実行する場合には、iオプションに空文字を渡さないでください(iはin-place置換です)。

まず、configという文字列を含むファイル一覧をプロジェクト直下からみておきます。 (ここで下の一覧に示すファイル以外が出てくるようなら、どこかで名前が被っているということなので気をつけて結果を確認してください。)

Djangoが新しいのでasgi.pyがありますね。

$ grep -rl 'config' --exclude-dir=env .
./config/asgi.py
./config/settings.py
./config/urls.py
./config/wsgi.py
./manage.py

以下のように置換します。(プロジェクトのディレクトリ==manage.pyがあるところ で実行してください)

$ grep -rl 'config' --exclude-dir=env . | xargs sed -i '' -e 's/config/{{ project_name }}/g'

ここでvenvは消しておきます。

# venvは消しておく必要があります。
$ rm -r env

テンプレートをもとに新規プロジェクト作成

方法

まずは新規ディレクトリを作り、仮想環境を作ってDjangoを入れます。 この手順はコピペで一気にできるので手間にはならないというのがポイントです!

# 先程さくせいしたテンプレートプロジェクトの一回層上に移動しました。
$ cd ..
$ ls -d tmp-template-project
tmp-template-project/

# 新しいプロジェクトのディレクトリを作り、移動します。
$ mkdir new-project-from-template
$ cd new-project-from-template/

# 仮想環境を作ります
$ python3 -m venv env
$ source env/bin/activate
$ pip install Django==3.0.7

startprojectをするときに、--template引数でテンプレートとなるプロジェクトを指定します。 このとき渡すプロジェクト名(下の例ではnew_project_name)が、プレースホルダ{{ project_name}}を置換します。

$ django-admin startproject --template ../tmp-template-project config .


# 先程のプロジェクトができている!
$ ls
cms/       config/    env/       manage.py*

config以外の名前でプロジェクトを立ち上げるときにはディレクトリ名に注意

新しいプロジェクトをconfig以外で作る場合はディレクトリ名だけ修正するように気をつけます。 他にも、このプロジェクトの設定を含むディレクトリ(config)の名前を使って記述する部分は漏れなく{{ project_name}}というテンプレート文字列で書くように気をつけます。 (grep & sedで一気に置換できるので、あまり意識せずテンプレートプロジェクトを作ってOKだと思います)

$ django-admin startproject --template ../tmp-template-project special_product .

# ディレクトリ名を修正する。
$ mv config special_product

その他のtemplate context を使ってみる

project_name意外にもテンプレートに渡されるコンテキストはいくつかあります。

django-admin and manage.py | Django documentation | Django

実際にみてみましょう。

以下のようなテキストをtmp-template-project/context_test.txtにおいてみます。

project_name : {{ project_name }}
project_directory: {{ project_directory }}
secret_key: {{ secret_key }}
docsversion: {{ docs_version }}
django_version: {{ django_version }}
bbbb

新しいプロジェクトを作成するとき、以下のようにオプションを指定します。

$ django-admin startproject\
     --template ../tmp-template-project \
     --extension py,txt --name context_test.txt \
     config .

結果、新しく作られたプロジェクトのcontext_test.txtは以下のようになります。 各種プレースホルダーが置換されているのがわかります。

project_name : config
project_directory: /Users/kyutatsu/Documents/web_development/new-project-from-template
secret_key: b!ui=x21xes*9$q^m_6=cvef(#28$0k&wjouy+5w8f+(ab6!3q
docsversion: 3.0
django_version: 3.0.7
bbbb