見出し画像

【サンプルコード付き】Django開発の効率化を図る小ネタ紹介

1. はじめに

こんにちは、ぎーたかです。

Django開発の節目の1つに”ローカルからテスト・本番サーバーに移行して稼働”というフェーズがあります。
いざ作業に取り掛かる際、もしくは過去に取り組んだ際には、特に疑問を持たずやっちゃう作業がいくつかあったと思います。

ただ、その作業、本当にやる必要があるでしょうか?

筆者もDjangoのポートフォリオの本番環境移行時には、テスト・本番環境の構築思考・意識が向いてしまい、やらなくてもいい作業に時間を使っちゃっていました。

実際は、やり方・ハウツーを知ってさえいれば、簡略化して実施できる作業なのですが、どうしても初学者の頃は機能開発の技術習得にばかり意識が行ってしまうので、なかなか習得する機会がないものです。

だからこの記事では、初学者向けのマガジンに寄稿する立場を生かして、初学者でも簡単に実践できる開発効率化のTipsを解説していきます。
どれも比較的簡単、かつサーバー移行の付き物作業に関するハウツーなので、少しばかり時間を割いて最後まで読んでいってくださると嬉しいです。

それでは実際に紹介していきましょう!

2. 取り上げるTipsの紹介

実際のサーバー移行に伴い発生する作業ケースごとに、”その作業、こうすれば効率化できるよ!”というTipsを紹介します。

具体的には以下のケースに対する効率化Tipsを紹介します。

■無駄作業例⇨効率化Tips
①ローカルでインストールしたライブラリ本番サーバで再インストール
 ⇨requirementsファイルで管理・一括インストール可能
テストサーバのデータベースに確認用の初期データを管理画面から再登録
 ⇨fixtureファイルで管理・一括投入可能
③各ファイルに記述したパスワード等をGit共有前に消去、デプロイ後再記入
 ⇨.envファイル管理・本番サーバーでもコピペで簡単作成

③に関しては、Gitクライアント経由でパブリックリポジトリを使って本番サーバーへ転送する方以外(SFTP転送・サーバーサービス特有のストレージ機能(例. AWSのS3等)をお使いの方)には、当てはまらない無駄作業かもしれませんね。

読者の皆さんも、あまり気に留めずやってる作業が1つくらいはあるのではないでしょうか?
これらの作業は環境移行時に毎回発生してしまうので、長いWEB開発人生を考えると、可能な限り必要作業を最小化しておいた方がいいですよね。

次の章からは、ケース①から効率化Tipsを詳しく解説していきます。
もし、①〜③に当てはまるケースがある場合は、この記事を通してハウツーを習得して、ご自身のDjango開発をより効率化していってください!

なお、複数人でのチーム開発を行う場合も、これらの技術で開発・テスト環境の共通化を行える副次的な効果が生まれます。
チーム開発を見据えている方も、ぜひマスターしていってくださいね!

3. requirementsファイルによる使用ライブラリ管理

■使用準備
プロジェクト直下のmanage.pyがある階層で、ターミナルで以下のコマンドを実行します。

$pip freeze > requirements.txt

すると、プロジェクト直下の階層にrequirements.txtというファイルが作られます。

#構成イメージ
project
|-config    #設定ディレクトリ(settings.pyなどあるところ)
|  '...
|-app1      #アプリディレクトリ①
|  '...
...         #アプリディレクトリ、templates/static/mediaディレクトリ、その他ファイルが続く
|
|-manage.py
'-requirements.txt    #追加 ライブラリ管理ファイル

■使い方
作成したrequirements.txtを確認してみましょう。

◎requirements.txt

...
Django==3.1.3
django-allauth==0.44.0
django-ckeditor==6.0.0
django-environ==0.4.5
django-js-asset==1.2.2
django-sendgrid-v5==0.9.1
django-sslserver==0.22
...

といった様に、コマンドを入力した環境にインストールされたライブラリが列挙されています。(※pip経由でインストールしたものに限ります)

他の環境で、全く同じライブラリリストを一括でインストールするためには

$pip install -r requirements.txt

と入力すれば、requirements.txt記載のライブラリリストをバージョンも揃えて、インストールすることができます。

ただ、コマンドを叩いてすぐのrequirements.txtのリストには、Djangoでは不要なライブラリが含まれていることも多いです。
pipはPython全体のライブラリ用のインストールコマンドのため、Djangoに限らずローカル環境で使ったライブラリを全てをファイルに吐き出します。

不要なライブラリがないか、さっと確認したのちに環境移行先のPCでコマンド実行する方がベターでしょう。

■補足
バージョン指定には、requirements.txt上の記述方法で、より柔軟に指定できます。バージョン指定の規則は、ライブラリ名に続く”記号”・”バージョン”の組み合わせで定まります。

表でまとめると、以下の通りになります。
環境間で差異を出したくなければ、==で記述するのが一番ですね。
ただ、利用可能なバージョンのサポートが切れるとインストールできなくなるので、サポート範囲ギリギリの古いバージョンを使うのはあまりオススメしません。

requirementsバージョン指定

■その他、参考記事
紹介内容をざっくり解説した参考記事を掲載しておきます。
もし筆者の説明でよくわからなかった場合は、一度こちらも読んでみると良いかと思います。

4. fixtureファイルによるテスト用初期データ管理

■使用準備
先程のプロジェクトディレクトリをベースに解説します。
初期データのためのファイルは、アプリフォルダごとに必要です。
以下の例では、アプリディレクトリ①用の初期データ準備のため、fixtureディレクトリ・fixture_app1.jsonファイルを作成しています。

このように、データを投入したいモデルを含むアプリディレクトリ直下にfixtureディレクトリ・ファイルを追加し、このファイルに追加データの情報入力していくことで、データ投入の準備が整うことになります。

#構成イメージ
project
|-config    #設定ディレクトリ(settings.pyなどあるところ)
|  '...
|-app1      #アプリディレクトリ①
|  |...     #諸々ファイル
|  '-fuxture                #追加 初期データファイル用のディレクトリ
|     '-fixture_app1.json   #追加 app1の初期データファイル
|
...         #アプリディレクトリ、templates/static/mediaディレクトリ、その他ファイルが続く
|
|-manage.py
'-requirements.txt    #ライブラリ管理ファイル

■使い方
まず、fixture_app.jsonファイルにデータの情報を入力していきます。

◎前提
app1ディレクトリのmodels.pyには、Postモデルが定義されているものとします。また、Postモデルにはタイトルを入力するtitleフィールドと、内容を入力するcontentフィールドがあるものとします。

◎記述例

[
    {
        "model": "app1.post",
        "pk": 1,
        "fields": {
            "title": "テスト投稿",
            "content": "Postアプリの挙動確認のためにテストデータとして作成しました。"
        }
    }
    # ... 同様にモデル名、pk値、フィールドを定義したデータを追加していく
]

◎投入方法
データを作成し終わったら、migrations⇨migrateコマンドモデルの状態を最新にし、初期データ投入用のコマンドを入力します。

$python manage.py loaddata fixture_app.json    #ファイル名を指定してロード

このコマンドが正常終了すれば、データベースに初期データの投入が完了します。このテクニックを使いこなせる様になれば、初期データの投入に時間を奪われることはなくなりますね!

ただ、吐き出し直後のjsonファイルは1行にぎっしり書かれていて、読めたものではないです。もしエディタにVScodeをお使いなら、デフォルトのフォーマット機能があるので、以下の記事を参考に整形してみましょう。
VScode以外をお使いの方も、そのさらに下のサイトなら整形したコードを抽出可能かと思います。”Text”タブにコピペして"Format"ボタンを押すだけなので、ぜひ使ってみてください!

もし、管理画面からポチポチとデータを作成している方がいれば、本当に時間の節約になるかと思いますので、ぜひ習得して欲しいです!

■補足
初学者目線
からすると、完全に0からのfixtureファイルの記述はハードルが高いと感じるかもしれません。
なので、筆者はfixtureのフォーマットターミナルコマンドで作ってから、追記していく作業スタイルをオススメします。

流れを少し整理しておくと、
①フォーマット用データ作成
⇨データ作成はDjango管理画面・シェル・WEBアプリページから実施
②フォーマット用データからfixtureファイルへ吐き出し
⇨空のfixtureファイルを作成し、コマンドでfixtureファイルに吐き出し
(.(モデル名)を省略すると、アプリに紐づく全モデルのデータを吐き出し対象にできます。)

$python manage.py dumpdata (アプリ名).(モデル名) -> (アプリ名)/(fixtureファイル名)

③初期データファイルの作り込み
⇨作成されたフォーマットをコピペで複製して、テスト用データを作成
④環境移行時にデータを投入
⇨上述のloaddataコマンドでデータを投入

といった流れで、簡単にfixtureファイルを作成できるかと思います。
注意点は、dumpdataコマンドの効果で、”実行された瞬間にデータベースに含まれるデータを指定ファイルに吐き出す”という処理になっています。
そのため、追記したデータはすぐにloaddataコマンドでアプリに投入しておかないと、もう一度dumpdataコマンド実行時に消えてしまうので、管理には注意しましょう。

■その他、参考記事
紹介内容をざっくり解説した参考記事を掲載しておきます。
もし筆者の説明でよくわからなかった場合は、一度こちらも読んでみると良いかと思います。

5. .envファイルによる秘密キーの一元管理

■使用準備
先程のプロジェクトディレクトリをベースに解説します。
アプリディレクトリ直下.envファイルを作成しておきます。

#構成イメージ
project
|-config    #設定ディレクトリ(settings.pyなどあるところ)
|  '...
|-app1      #アプリディレクトリ①
|  |...     #諸々ファイル
|  '-fuxture                #初期データファイル用のディレクトリ
|     '-fixture_app1.json   #app1の初期データファイル
|
...         #アプリディレクトリ、templates/static/mediaディレクトリ、その他ファイルが続く
|
|-manage.py
|-requirements.txt    #ライブラリ管理ファイル
'-.env                #追加 秘密キーの一元管理ファイル

また、機能の利用にはdjango-environというライブラリが必要なので、pipコマンドでインストールしておきます。

$pip install django-environ    #一元管理の機能のために追加

■使い方
もともと、以下の様なファイルがあった前提で使い方を解説します。

◎前提ファイル(settings.pyなど)

...
#何かのAPIサービスの認証キーとして ACCESS_KEY, SECRET_KEYをベタ打ち
ACCESS_KEY='xxxxxxxxxxxxxxxx'
SECRET_KEY='xxxxxxxxxxxxxxxx'
...

この例のダメな点を指摘すると、何かのサービスにアクセスするための秘密キーをファイルに直接書き込むのは、セキュリティや開発効率の観点からあまりやらない方がいいです。

もし、このファイルをそのまま環境移行先に転送する場合は、ネットに秘密キーの情報を通すことになるので、アカウント乗っ取りに悪用される可能性があります。
また、環境移行先に転送前に、各ファイルを確認して一度記述したキー情報を削除して転送して転送後に追記する場合も、削除の抜け漏れがあればセキュリティ的に問題ですし、普通に面倒ですよね。

そうした問題を解決するために、以下の様に書き換えましょう。

◎記述方法

・.envファイル(※.envでは文字列を''で囲わないので注意)

ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxx
SECRET_KEY=xxxxxxxxxxxxxxxxxxxxx

・settings.pyなど

#environライブラリの使用を宣言
import environ

#変数envに.envで記述した秘密キーなどを辞書型で格納する
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, '.env'))

...
#envを使って書き換え
ACCESS_KEY=env('ACCESS_KEY')
SECRET_KEY=env('SECRET_KEY')
...

この様にすれば、秘密キーを一元管理できます。
環境移行に伴い気にすれば良いファイルが1ファイルに限定されるので、複数ファイルに秘密キーを書く必要がある場合も、.envファイル以外はそのまま転送できる点は効率化のメリットが大きいです。

ぜひ、.envファイルの扱いも習得していただき、より効率的なDjango開発に生かしていただけると嬉しいです。

■補足
もし開発ファイルをGitHubなどのバージョン管理ツールにアップロードしている場合は、.gitignoreファイルも作成して.envファイルをGitの対象から外しておきましょう。
難しいことを言ってるように聞こえるかもですが、手順はめちゃくちゃ簡単です。
①プロジェクトディレクトリ直下に空の.gitignoreファイルを作成
②ファイルに.envとだけ書いた行を追加

設定をしない限り、git add .をコマンドで叩こうものならせっかくの.envファイもインターネットにアップされかねません。Gitを使った管理をしている方は、ぜひ下の記事も参考にしながら設定してみてください。

■その他、参考記事
紹介内容をざっくり解説した参考記事を掲載しておきます。
もし筆者の説明でよくわからなかった場合は、一度こちらも読んでみると良いかと思います。

6. おまけ ~context_processors~

今回記事の作成にあたるGoogle先生への取材活動を通して、筆者も改めて効率化Tipsの勉強になりました!

その中で、環境移行には関係ないですが、開発効率化のTipsとして簡単かつ便利なものを見つけたので、ここで1つ紹介しようと思います。

■無駄作業⇨効率化Tips
・どのテンプレートにも共通で渡したい変数を、全てのviewで引数に宣言
⇨context_processors.pyに記述し、デフォルトで渡される引数を設定する

■使用準備
templatesディレクトリに空のcontext_processors.pyファイルを作成します。

#構成イメージ
project
|-config    #設定ディレクトリ(settings.pyなどあるところ)
|  '...
|-app1      #アプリディレクトリ①
|  |...     #諸々ファイル
|  '-fuxture                #初期データファイル用のディレクトリ
|     '-fixture_app1.json   #app1の初期データファイル
|
...         #アプリディレクトリ、templates/static/mediaディレクトリ、その他ファイルが続く
|
|-templates
|  |-...                    #諸テンプレートファイル
|  '-context_processors.py  #追加 デフォルト引数設定用のファイル
|
|-manage.py
|-requirements.txt    #ライブラリ管理ファイル
'-.env                #秘密キーの一元管理ファイル

■使い方
context_processors.pyを編集していきましょう。

#requestの発生に伴い呼ばれる関数を定義
def default_context(request):
    ...                                    #テンプレートに渡す引数を生成する処理など
    return {'DEFAULT_CONTEXT': '...'}      #DEFAULT_CONTEXTをキーに持つ形で引数として渡す

また、settings.pyファイルにcontext_processorsの読み込みを記述します。

...
TEMPLATES = [
   {
       'BACKEND': 'django.template.backends.django.DjangoTemplates',
       'DIRS': [BASE_DIR, 'templates'],
       'APP_DIRS': True,
       'OPTIONS': {
           'context_processors': [
               'django.template.context_processors.debug',
               'django.template.context_processors.request',
               'django.contrib.auth.context_processors.auth',
               'django.contrib.messages.context_processors.messages',
               'templates.context_processors.default_context'        #追加
           ],
       },
   },
]
...

テンプレート側に渡された引数を表示させたい場合は、{{ キー名 }}で表示可能です。例を書くと以下の様になります。

...
<div>{{ DEFAULT_CONTEXT }}<div>
...

簡単な割に、結構効果が大きいのではないかと筆者は感じました。
作成するWEBアプリにもよりますが、全ページ共通で使用するナビゲーションバーの表示内容を引数を渡して可変化しているシーンでは、この手法は大いに役立つかと思います。

この手法を取ることで、最悪の場合すべてのviewに引数として渡す処理の記述を完全になくすことができるので、必要に応じて活用していただけると嬉しいです。

7. 終わりに

今回の記事、いかがでしたか?

筆者自身のポートフォリオ作成の過程で、”もっと早く知っていればよかったなぁ”と感じたハウツーを今回紹介してきました。
また、筆者が調べた範囲の中でも、機能開発の技術力の高い低いに関わらず取り入れられるものに絞って紹介しました。

初学者の頃は、機能開発のための技術習得に必死で、なかなかこういうコーディングテクニックまで気を回して習得できないものです。が、”工夫次第で楽できる”というプログラミングの楽しさこそ、実は初学者の方にどんどん知って欲しい内容だと筆者は考えます。

ぜひ読者の皆さんも使いこなして、より楽しいWeb開発ライフを送っていただけると嬉しいです!

これからもDjangoの学習者・開発者に向けた、開発のサポートになる記事を作っていくので、もしよろしければこれからも読んでいっていただけると嬉しいです。

よろしければサポートをお願いします🙇‍♂️ いただいたサポートは、クリエイターの活動資金として使わせていただきます😌 活動を通してえた経験を、また記事として皆さんと共有します👍