Django への初めてのパッチを書く

はじめに

小さなものでも、コミュニティへ恩返しすることに興味がありますか? たとえば、Django に直してほしいバグを見つけたり、ちょっとした機能を追加してほしいと思っているかもしれません。

その願いを叶える一番の方法は Django 自体にコントリビュートすることです。最初はすごく大変なことだと想像するかもしれませんが、あなたを助けてくれるドキュメント、ツール、コミュニティとともに多くの人が通る道でもあります。これからコントリビュートのプロセス全体を順番に詳しく解説していくので、例を通して理解できると思います。

このチュートリアルの対象者は誰ですか?

参考

パッチを書く方法の細かい参照文献を探しているなら Writing code ドキュメントを参照してください。

このチュートリアルは、少なくとも Django が動作に関して基本的な理解があることを想定しています。つまりチュートリアル 初めての Django アプリ を十分に理解していることを想定しています。また、Python 自体もよく理解している必要があります。もしそうでない場合、 Dive Into Python というガイドがあります。これは Python プログラマーになるための素晴らしい (かつ無料の) オンラインドキュメントです。

バージョン管理システムや Trac をよく知らない方でも、このチュートリアルとリンク先から、コントリビュートに必要な情報は十分得られます。しかし、Django に定期的に貢献したい場合は、このツールの詳細を知っておいた方がいいでしょう。

このチュートリアルでは、できるだけ多くの方が使用できるように、可能な限り詳しく説明したいと思います。

困ったときは:

If you're having trouble going through this tutorial, please post a message to django-developers or drop by #django-dev on irc.libera.chat to chat with other Django users who might be able to help.

このチュートリアルはどの範囲をカバーしていますか?

初めて Django にパッチを送る手順までを詳しく解説しています。このチュートリアルを終えると、関連するツールとプロセス両方について基本的な理解が得られます。具体的には次が対象とする範囲です。

  • Git のインストール
  • Django 開発版の複製をダウンロードする
  • Django のテストスイートの実行
  • パッチへのテストを書く
  • パッチのコードを書く
  • パッチをテスト
  • プルリクエストを送る
  • より多くの情報を得る方法

チュートリアルを終えたら、次は Django への貢献 を参照してください。このドキュメントには、多くの重要な情報が含まれており、Django に定期的に貢献したい方は是非一読してください。あなたの疑問への答えが見つかるはずです。

3系の Python が必要です!

Django の現在のバージョンは、Python 2.7 をサポートしません。Python のダウンロードページ <https://www.python.org/downloads/> や OS のパッケージ管理システムを用いて Python 3 をインストールしてください。

Windows を使用している方へ

Windowsのドキュメントの Python をインストールする をみてください。

ソースコードの管理

あなたはコントリビューターとして私たちDjangoコミュニティをオープンかつ包摂的なものでありつづけることを援助できます。私たちの ソースコードの管理 <https://www.djangoproject.com/conduct/> を参照し、フォローして下さい。

Git のインストール

このチュートリアルでは、最新の Django 開発版のダウンロードとその変更のパッチファイルを生成するために Git をインストールする必要があります。

Git がインストールされているかどうかを確認するために、コマンドラインで git を入力します。もし入っていない場合は、ダウンロード及びインストールするために、 Git's download page を参照してください。

もし Git について詳しく知らない場合は、(インストール後に) コマンドラインから git help と入力するとコマンドの使い方を確認できます。

Django 開発版の複製を取得

Django へ貢献するためのはじめの一歩は、ソースコードのコピーです。まず、 GitHub で Django をフォーク して、コマンドラインからリポジトリのクローンを作り、 cd コマンドで Django のローカルコピーのディレクトリに移動しましょう。

以下のコマンドで Django のソースコードリポジトリをダウンロードします:

$ git clone https://github.com/YourGitHubName/django.git
...\> git clone https://github.com/YourGitHubName/django.git

低帯域の回線をご利用ですか?

git clone--depth 1 という引数を追加すると、Djangoのコミット履歴のダウンロードをスキップすることができます。これによってデータの転送量が70〜250MB程度減ります。

Django のローカルコピーがあるので、 pip を使ってパッケージをインストールするのと同じようにインストールすることができます。そのための最も便利な方法は、Python に組み込まれている機能である 仮想環境 を使用することです。これにより、相互に干渉しないようにプロジェクトごとにインストールされたパッケージの別々のディレクトリを保つことができます。

例えばホームディレクトリ下の .virtualenvs/ にすべての仮想環境を置くことが出来ます。

実行することによって、新しい仮想環境を作成します:

$ python3 -m venv ~/.virtualenvs/djangodev
...\> py -m venv %HOMEPATH%\.virtualenvs\djangodev

新しい環境があるパスはコンピュータに保存されました。

最後のステップとして仮想環境を有効化します:

$ source ~/.virtualenvs/djangodev/bin/activate

もし source コマンドが使えない場合、代わりに . を試してみてください:

$ . ~/.virtualenvs/djangodev/bin/activate

新しいターミナルウィンドウを開くたびに仮想環境を有効にする必要があります。

Windows を使用している方へ

実行してWindowsでの仮想環境を有効化します:

...\> %HOMEPATH%\.virtualenvs\djangodev\Scripts\activate.bat

その時点で有効な仮想環境の名前がコマンドライン上に表示されます。これによってどの仮想環境を利用しているのかが分かります。仮想環境のもとで pip によるインストールを行うと、表示されている仮想環境内にインストールされます。他の仮想環境やパッケージインストールによるシステムとは区別されます。

先に進んで、以前にクローンしたDjangoのコピーをインストールしてください:

$ python -m pip install -e /path/to/your/local/clone/django/
...\> py -m pip install -e \path\to\your\local\clone\django\

Django のインストール済みバージョンは、編集可能モードでインストールすることにより、ローカルコピーを指すようになりました。変更内容はすぐに反映されます。これは最初のパッチを作成する際に非常に役立ちます。

ローカルに複製した Django でプロジェクトを作成する

Djangoプロジェクトでローカルの変更をテストすると役立つ場合があります。 最初に、新しい仮想環境を作成する必要があります install the previously cloned local copy of Django in editable mode、ローカルにコピーしたDjangoの外部に新しいDjangoプロジェクトを作成します。 新しいプロジェクトでDjangoに加えた変更はすぐに表示されます。これは、最初のパッチを作成するときに非常に役立ちます。

最初に Django のテストスイートを実行する

Django に貢献する際には、コードの変更が Django の他の領域にバグを持ち込まないようにすることが非常に重要です。変更を行った後もDjangoが動作するかどうかを確認する方法の1つは、Djangoのテストスイートを実行することです。すべてのテストに合格していれば、あなたの変更が機能し、Django の他の部分を壊していないことを合理的に確認することができます。 Django のテストスイートを実行したことがない人は、事前に一度実行して出力に慣れておくと良いでしょう。

Before running the test suite, enter the Django tests/ directory using the cd tests command, and install test dependencies by running:

$ python -m pip install -r requirements/py3.txt
...\> py -m pip install -r requirements\py3.txt

If you encounter an error during the installation, your system might be missing a dependency for one or more of the Python packages. Consult the failing package's documentation or search the web with the error message that you encounter.

テストスイートを実効する準備が出来ました。もし GNU/Linux, macOS 等 Unix 系OSを使用している場合、下記のコマンドを実行します:

$ ./runtests.py
...\> runtests.py 

さあ、座ってリラックスしてください。Django のテストスイート全体には何千ものテストがあり、コンピュータの速度にもよりますが、実行には少なくとも数分かかります。

Django のテストスイートを実行中に、各テストの完了時のステータスを表す一連の文字が表示されます。 E はテストにエラーが発生したことを表し、 F はテストのアサーションが失敗したことを表しています。これらは共にテスト失敗となります。xs はそれぞれ期待する失敗とスキップを表しています。ドットはテストの成功を表しています。

スキップされたテストは、テストを実行するために必要な外部ライブラリがインストールされていないことが原因です; 依存については Running all the tests を参照し、あなたの変更に関連するテストにする依存ライブラリがインストールしてください (このチュートリアルでは必要ありません)。いくつかのテストは、特定のデータベースバックエンドに固有であり、そのバックエンドでテストされない場合はスキップされます。 SQLite は、デフォルト設定のバックエンドです。別のバックエンドを使用してテストを実行するには、 Using another settings module を参照してください。

テストが終了するとテストが成功したか、失敗したかを知らせるメッセージが表示されます。まだ Django のコードに変更を加えていなければ、テストは全て パスするはずです 。もし失敗するかエラーが起こる場合は、これまでの全ステップを適切に実行してください。 Running the unit tests で、よりテストについて知れます。

最新の Django の main ブランチは常に安定しているとは限りません。 main バージョンで開発を行う場合、 Django の継続インテグレーションビルド をチェックしてください。これで、テストの失敗があなたのマシンだけのものか、 Django 公式のビルドによるものかが分かります。各ビルドについてのリンクをクリックすれば、 "Configuration Matrix" という、各 Python のバージョン、 DB バックエンドに対応したテストの失敗を閲覧できます。

注釈

このチュートリアルや、各チケットで作業する際は、 SQLite のテストで十分です。しかし可能(か必要)な場合は 他のデータベースでテストを実行する を参照してください。

取りかかる

このチュートリアルでは、ケーススタディとして「架空のチケット」を使って作業を進めます。以下はその架空の詳細です。

チケット #99999 -- トーストを焼くようにする

Django は、toast を返す関数 django.shortcuts.make_toast() を提供しなければなりません。

これよりこの機能と関連するテストを実装します。

パッチ用のブランチを作る

変更を加える前に、チケット用に新しいブランチを作ります。

$ git checkout -b ticket_99999
...\> git checkout -b ticket_99999

ブランチ名は好きな名前で構いません。"ticket_99999" は一例です。新しいブランチ内で行ったすべての変更は、先ほどクローンしたコードのマスターコピーには影響しません。

チケットにテストを書く

大抵の場合、 Django にアクセプトされるパッチはテストを含んでいます。バグフィックス修正の場合、リグレッションテストを書くことで、 Django にバグを再混入していないと後に保証できます。リグレッションテストは、バグが存在しているときに落ちるように書き、バグが修正された後にパスするように書かれるべきです。新機能を含むパッチでは、その新機能が正しく動作すると保証するためにテストが必要です。その際も同じように、テストは、新機能がない段階では落ち、実装されたら通るべきです。

これをするには、コードに変更を加える前に先にテストを書くのが良いでしょう。この開発手法は テスト駆動開発 と呼ばれ、プロジェクト全体にも単一のパッチにも適応可能です。テストを書いた後には、テストを走らせて確かに落ちることを確認します (バグ修正や機能の追加はまだしてないので落ちます)。新しいテストが落ちない場合は落ちるよう修正しましょう。ともかく、バグが存在していようとも通るテストは将来バグが再発するのを防ぐのに何の役にもたちません。

ハンズオンでの例題に移りましょう。

チケット #99999 に対するテストの実装

In order to resolve this ticket, we'll add a make_toast() function to the django.shortcuts module. First we are going to write a test that tries to use the function and check that its output looks correct.

Djangoの tests/shortcuts/ フォルダへ移動して test_make_toast.py というファイルを新たに作ります。以下のコードを追加してください。

from django.shortcuts import make_toast
from django.test import SimpleTestCase


class MakeToastTests(SimpleTestCase):
    def test_make_toast(self):
        self.assertEqual(make_toast(), 'toast')

このテストは make_toast()toast を返すかを確認します。

でもテストをするのはすこし難しそうです……

テストを書いたことがない場合は、最初は難しく見えるかもしれません。ですが実は、テストすることはプログラミングにおいて とても 重要なことです。ここではテストについて詳細に紹介します。

  • Django のための良いテストの書き方は テストを書いて実行する のドキュメントに記載されています。
  • Dive Into Python (Python初心者のための、オンラインの無料の本) には素晴らしい 初めてのユニットテスト という章があります。
  • Dive Into Python を読んだあと、もう少し情報が欲しい場合は、Python の unittest のドキュメントを参照してください。

新しいテストを走らせる

まだ django.shortcuts に変更を加えていないため、テストは失敗します。 shortcuts フォルダ内の全てのテストを実行して、どうなるか見てみましょう。 cd でDjangoの tests/ ディレクトリへと移動してから実行してください。

$ ./runtests.py shortcuts
...\> runtests.py shortcuts

テストが正しく実行されれば追加したテストメソッドに対して、こちらのエラーとともに1つテストが失敗しているはずです。

ImportError: cannot import name 'make_toast' from 'django.shortcuts'

テストがすべて通れば、上記した新しいテストを正しいフォルダ、クラスに追加したことを確認してください。

チケットにコードを書く

続いては make_toast() 関数を追加します。

django/ フォルダに移動して shortcuts.py ファイルを開きます。最下行に以下を追加します:

def make_toast():
    return 'toast'

さて、先ほど書いたテストが成功したことを確認する必要があるので、追加したコードが正しく機能しているかどうかを確認できます。もう一度、Django の tests/ ディレクトリに移動して以下を実行します:

$ ./runtests.py shortcuts
...\> runtests.py shortcuts

テストはすべて成功するはずです。失敗した場合は、正しいファイルに対して正しく関数を追加しているかどうかを確認してください。

Django の テストスイートをもう一度走らせる

パッチとテストが正しく機能していることを確認したら、Djangoテストスイート全体を実行して、変更によってDjangoの他の領域にバグが発生していないことを確認することをお勧めします。 テストスイート全体に合格しても、コードにバグがないことが保証されるわけではありませんが、見過ごされる可能性のある多くのバグやリグレッションを特定するのに役立ちます。

Django の全てのテストスイートを走らせるには cd で Django の tests/ ディレクトリ移動して実行してください:

$ ./runtests.py
...\> runtests.py 

ドキュメントを書く

これは新たな機能です。したがってドキュメントを作る必要があります。ファイル docs/topics/http/shortcuts.txt を開いて、このファイルの最終行に以下を加えます。

``make_toast()``
================

.. function:: make_toast()

.. versionadded:: 2.2

Returns ``'toast'``.

この新機能は将来のリリースとともに、Django 次期バージョンのリリースノートにも含まれます。ファイル docs/releases/ の最新バージョン (これを書いてる時点では 2.2.txt) のリリースノートを開き、"Minor Feature" ヘッダの下にノートを追記してください。

:mod:`django.shortcuts`
~~~~~~~~~~~~~~~~~~~~~~~

* The new :func:`django.shortcuts.make_toast` function returns ``'toast'``.

ドキュメントの書き方についてもっと知りたい場合は Writing documentation を参照してください。ここでは、 versionadded の書き方についてや、 ドキュメントのコピーをローカルでビルドしてみて、 HTML をプレビューする方法などが書かれています。

変更点を確認する

パッチに加えた修正をすべて確認することにしましょう。

$ git add --all
...\> git add --all

上により Django のカレントコピー (修正内容を含む) と、チュートリアル冒頭において行っていたチェックアウトリビジョンとの違いが表示されます。

$ git diff --cached
...\> git diff --cached

ページを進めるには上下キーを使います。

diff --git a/django/shortcuts.py b/django/shortcuts.py
index 7ab1df0e9d..8dde9e28d9 100644
--- a/django/shortcuts.py
+++ b/django/shortcuts.py
@@ -156,3 +156,7 @@ def resolve_url(to, *args, **kwargs):

     # Finally, fall back and assume it's a URL
     return to
+
+
+def make_toast():
+    return 'toast'
diff --git a/docs/releases/2.2.txt b/docs/releases/2.2.txt
index 7d85d30c4a..81518187b3 100644
--- a/docs/releases/2.2.txt
+++ b/docs/releases/2.2.txt
@@ -40,6 +40,11 @@ database constraints. Constraints are added to models using the
 Minor features
 --------------

+:mod:`django.shortcuts`
+~~~~~~~~~~~~~~~~~~~~~~~
+
+* The new :func:`django.shortcuts.make_toast` function returns ``'toast'``.
+
 :mod:`django.contrib.admin`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~

diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt
index 7b3a3a2c00..711bf6bb6d 100644
--- a/docs/topics/http/shortcuts.txt
+++ b/docs/topics/http/shortcuts.txt
@@ -271,3 +271,12 @@ This example is equivalent to::
         my_objects = list(MyModel.objects.filter(published=True))
         if not my_objects:
             raise Http404("No MyModel matches the given query.")
+
+``make_toast()``
+================
+
+.. function:: make_toast()
+
+.. versionadded:: 2.2
+
+Returns ``'toast'``.
diff --git a/tests/shortcuts/test_make_toast.py b/tests/shortcuts/test_make_toast.py
new file mode 100644
index 0000000000..6f4c627b6e
--- /dev/null
+++ b/tests/shortcuts/test_make_toast.py
@@ -0,0 +1,7 @@
+from django.shortcuts import make_toast
+from django.test import SimpleTestCase
+
+
+class MakeToastTests(SimpleTestCase):
+    def test_make_toast(self):
+        self.assertEqual(make_toast(), 'toast')

パッチのプレビューが終わったら q キーを押してコマンドラインに戻ります。パッチに問題がなければ、変更をコミットしましょう。

パッチの変更点をコミットする

変更点をコミットするには、次のコマンドを実行します。

$ git commit
...\> git commit

すると、コミットメッセージを入力するためのテキストエディタが開きます。 コミットメッセージガイドライン に従って、次のようにメッセージを入力します。

Fixed #99999 -- Added a shortcut function to make toast.

コミットのプッシュとプルリクエストの作成

パッチをコミットしたら、そのコミットを GitHub 上のあなたのフォークに送りましょう (ブランチ名を変えた場合には "ticket_99999" の部分を置き換えてください)。

$ git push origin ticket_99999
...\> git push origin ticket_99999

プルリクエストは Django の GitHub ページ から作成できます。"Your recently pushed branches" の下にあなたのブランチが表示されているはずです。その下の "Compare & pull request" ボタンをクリックします。

このチュートリアルでは行ってはいけませんが、次のページにパッチのプレビューが表示されるので、"Create pull request" をクリックすれば、Django プロジェクトに実際にプルリクエストを送ることができます。

次のステップ

おめでとうございます! これで Django へのプルリクエストの作成方法を学ぶことができました。応用テクニックについて詳しくは Working with Git and GitHub を読んでください。

これで、Django のコードベースを改良する手助けができるようになりました。

新しい貢献者のための情報

Django へのパッチを書き始める前に、貢献するために見ておいたほうがいい情報があります:

実際にチケットを探してみましょう

ドキュメントをたくさん読んだ後は、実際のパッチを書けるのでチケットを探してみましょう。 "easy picking" タグが付いたチケットを見つけてください。このチケットは大抵はより簡単なものなので、初めての貢献者には適切でしょう。 Django への貢献に慣れてきたあとは、難しく、複雑なチケットを書き始めれるでしょう。

もし今すぐ始めたいなら (責める人はいません!)、 パッチが必要な簡単なチケットパッチに改善が必要な簡単なチケット を見つけましょう。テストを書きなれているなら テストが必要な簡単なチケット でもよいでしょう。ただ、チケットのクレームに関するガイドラインに従うことを忘れないでください。 Django ドキュメントの チケットをクレームしてパッチを送る で記述されています。

プルリクエストを作ったあとは?

チケットに対してパッチを作ったら、他の人によるレビューが必要です。プルリクエストを送った後は、チケットのメタデータを "has patch"、"doesn't need tests" などのフラグを付けてアップデートして、他の人にレビューが必要だと分かるようにしてください。プロジェクトへの貢献は、必ずしもパッチを書くことだけではありません。すでに書かれたパッチをレビューのレビューもとても助かります。詳しくは Triaging tickets を見てください。