Django 2.0.1 官方文檔翻譯:編寫你的第一個djang補丁(page 15)

編寫你的第一個djang補丁(page 15)

介紹

有興趣爲社區作一些貢獻?可能你發現了django中的一個你想修復的bug,或者你你想添加一個小小的功能。html

回饋django就是解決你遇到的問題的最好的方法。一開始這可能會讓你望而生畏,但它真的很簡單。咱們會帶你熟悉整個過程,因此你能夠經過例子來學習。node

本節教程面向的誰呢?

另請參見
若是你在尋找如何提交更新的參考資料,請查看文檔Submitting patches(少一個連接)python

在本節教程,咱們假設你對django如何工做至少有了一個基本的瞭解。也就是說,你應該已經熟悉了已有的編寫你的第一個django app的教程。另外,你應該對python自己有很好的理解。但若是你不熟悉,Dive Into Python是一本很是棒(且免費)的爲python程序員新手準備的在線電子書。git

對於不熟悉版本控系統和Trac的人來講,會發現本教程和他的連接包含足夠的讓你開始學習的信息。無論怎樣,若是你計劃按期爲django貢獻,你可能會想閱讀更多關於這些不一樣工具的內容。程序員

不過,大部分狀況下,本教程試圖儘量多的去解釋,以它能夠用於最普遍的讀者,github

從哪裏獲取幫助:
若是你在使用本教程時遇到麻煩,請提交信息給django開發者或者登錄到 #django-dev on irc.freenode.net向有可能幫助你的django使用者尋求幫助。shell

本教程包含哪些內容?

第一次,咱們會帶領你給django編寫一個補丁,教程的最後,你應該對涉及的工具和流程有一個基本的理解。具體來講,咱們會涵蓋一下內容:數據庫

  • 安裝Git
  • 如何下載django的開發副本
  • 運行django的測試套件
  • 爲你的補丁寫一個測試
  • 爲你的補丁編寫代碼
  • 測試你的補丁
  • 提交一個pull請求
  • 去哪查找更多的信息

一旦你完成本教程,你就能夠學習剩下的 Django’s documentation on contributing了。它包含了大量信息,全部想變成django貢獻者的人都必須閱讀它。若是你遇到問題,它可能會給你答案。django

須要使用python3
當前版本的django再也不支持python2.7。去python下載頁或者你的操做系統的包管理器獲取python3。
windows用戶
在windows中安裝python時,去報你選中了「Add python.exe to Path」選項,這樣在命令行就老是有效的了編程

代碼規範

做爲一個貢獻者,你能夠幫助咱們保持django社區的開放性和包容性,請閱讀咱們的代碼規範

安裝Git

在本教程中,你須要安裝Git如下載django當前的開發版本,併爲你作的更改生成補丁文件。

檢查你是否已經安裝it,在命令行中輸入git。若是你獲得的信息是找不到這個命令。你必須去下載並安裝它,請參閱 Git下載頁

windows用戶
在windows上安裝Git時,建議選擇「Git Bash」選項,這樣Git就會運行在它本身的shell中。本教程假定你已經安裝它。

若是你不熟悉Git,你能夠經過在命令行輸入git help來找出更多關於它的命令。

獲取django開發版本的一個副本

爲django作出共享的第一步是獲取源代碼副本。首先fork Django on GitHub。而後,在命令行,使用cd命令進入你想要存放本地django副本的目錄。
使用下面的命令下載django源代碼庫:

$ git clone git@github.com:YourGitHubName/django.git

如今你就有了一份django的本地副本,你能夠安裝它,就像你使用pip安裝其餘的包同樣。最方便的方式是使用虛擬環境(或者virtualenv),虛擬環境是python的內置特性,它容許你爲每個項目保留一個單獨的安裝包目錄,這樣項目之間就不會互相干擾。
有一個好主意是把你的全部virtualenv保存在一個位置。例如,在你家目錄下的.virtualenvs/中。若是不存在就建立它:

$ mkdir ~/.virtualenvs

如今經過下面的命令建立一個新的virtualenv:

python3 -m venv ~/.virtualenvs/djangodev

新環境的路徑位置會保存在你的計算機中

windows用戶
若是你在windows中使用 Git Bash shell,那麼內置的venv模塊會沒法工做。由於激活腳本僅僅支持系統shell(.bat)和PowerShell (.ps1)。可使用virtualenv來代替它

$ pip install virtualenv
$ virtualenv ~/.virtualenvs/djangodev

Ubuntu用戶
在某些版本的ubuntu中上面的命令可能會失敗。可使用virtualenv來替代,首先要去報你已經安裝了pip3

$ sudo apt-get install python3-pip
$ # Prefix the next command with sudo if it gives a permission denied error
$ pip3 install virtualenv
$ virtualenv --python=`which python3` ~/.virtualenvs/djangodev

設置vitualenv的最後一步是激活它:

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

若是source命令無效,你能夠嘗試用一個點來替代:

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

windows用戶
在windows中激活你的virtualenv,運行下面的命令:

$ source ~/virtualenvs/djangodev/Scripts/activate

不管什麼時候,打開一個新的終端窗口,你就必須激活virtualenv。virtualenvwrapper是一個使這個操做更方便的很是有用的工具。

從如今開始,全部你經過pip安裝的包都會安裝到你的新virtualenv裏,與其餘環境和整個系統的包隔離開來。另外,當前激活的virtualenv的名字會在命令行中顯示,以幫助你監看你正在使用的那一個。繼續並安裝前面克隆的django副本:

$ pip install -e /path/to/your/local/clone/django/

如今安裝的django版本指向你的本地副本。你能夠馬上看到你對它作的任何更改,在你在第一個補丁的時候這會有對你很是大的幫助。

回滾到以前的django版本

在本教程中,咱們將使用#24788來做爲學習用例,所以咱們須要把git中django的版本回滾到問題補丁沒有提交以前的版本。這會讓咱們參與進從頭開始編寫補丁的全部步驟中,包括正在運行的django測試組件。

請記住,雖然外面將在下面的教程中使用舊的django主幹版本,但在處理本身的補丁時,你應該始終使用django的當前開發版本

注意
這裏的補丁由Paweł Marczewski編寫,並已經應用於django,提交標記4df7e8483b2679fc1cba3410f08960bac6f51115,所以,咱們將使用在此以前的django版本,4ccfc4439a7add24f8db4ef3960d02ef8ae09887.

導航到djanmgo的根目錄(它是包含django, docs, tests, AUTHORS等的目錄)。你能夠檢出咱們將在下面的教程中使用的django的舊版本:

git checkout 4ccfc4439a7add24f8db4ef3960d02ef8ae09887

第一次運行django的測試組件

在爲django貢獻代碼時,很是重要的一點就是你的代碼不要爲django的其餘部分引入bug。一種辦法就是在你作了更改以後,運行django的測試組件,檢查django是否能夠正常工做。若是全部的測試都經過了,那麼你有理由確信你的更改徹底沒有破壞django。若是你之前從未運行過django的測試組件,事先運行一次,以熟悉它的輸出是什麼樣子的,會是一個很好的注意。
運行測試組件以前,先進入django的tests目錄,並運行下面的命令安裝依賴:

$ pip install -r requirements/py3.txt

若是在安裝期間你忽然遇到一個錯誤,這多是你的系統沒有安裝一個或多個python包的依賴。請查閱失敗包的文檔或者在網上搜索你遇到的錯誤信息。

如今,咱們準備肉運行測試組件,若是你使用的是GNU/Linux, macOS或者其餘的UYnix版本,運行下面的命令:

$ ./runtests.py

如今坐下來放鬆一下,django的所有測試組件有超過9600中測試,所以,他可能須要運行5到15分鐘,固然,這取決於你的計算機的速度。

當django的測試組件運行的時候,你能夠看一個顯示每一個測試用例狀態的字符串流。E 表示測試期間出現了一個錯誤,F 表示測試的斷言失敗。這兩種狀況都被認爲是測試失敗。同時,xs 分別表示預期的失敗和跳過的測試,圓點則表示測試經過。

跳過的測試一般是由於缺乏運行測試的外部庫;請檢查運行全部測試須要使用的依賴的列表,確保安裝了全部與你正在修改的相關的測試測全部依賴(本教程不須要額外安裝任何依賴)。一些特定的測試用於測試數據庫後端,若是不作後端測試,那麼就會被跳過。SQLite是默認的數據庫後端。運行其餘後端的測試,請參閱https://docs.djangoproject.com/en/2.0/internals/contributing/writing-code/unit-tests/

一旦測試完成,你應該會收到一條消息,通知你測試套件經過仍是未經過。因爲你還沒有對django的代碼作任何更改,測試應該是經過的。若是遇到失敗或者錯誤,請確保你按照前面步驟執行了全部操做。更多的信息請查看https://docs.djangoproject.com/en/2.0/internals/contributing/writing-code/unit-tests/。若是你使用的是Python 3.5+,你會遇到一些能夠忽略的與棄用相關的失敗內容,這些失敗內容已經在django中進行了修復。

注意,最新的django主幹版本可能不是穩定版。當針對主幹進行開發時,你能夠先檢查一下django的持續集成,以肯定故障是否僅在你的機器上發生,或者是否他們也存在於django的官方構建中。若是點擊了查看特定構建,則能夠看到「Configuration Matrix」,其中顯示了細分後的關於Python版本和數據庫後端的故障信息。

注意
對於本教程和正在處理的故障問題,測試SQLite是足夠了,可是還有可能使用不一樣的數據庫後端進行測試(有時測試必須的)。

爲你的更新建立一個分支

在作出更改前,先爲你的故障建立一個分支:

$ git checkout -b ticket_24788

你能夠隨意爲你的分支命名,「ticket_24788」僅僅是一個示例。在這個分支中,全部的更改都只針對前面遇到的故障,且不會影響到以前咱們克隆的代碼的主副本。

爲故障編寫測試

在大多數狀況下,對於要接受的django補丁,必須包含測試用例。對於bug修復補丁來講,編寫回歸測試以確保這個bug之後不會再從新被引入django中。迴歸測試要寫成的樣子是 bug存在時會失敗,bug修復後會經過。對於包含新功能的補丁,你須要包含保證新功能正常工做的測試。他們也應該在新功能不存在時失敗,新功能實現後經過。

實現這種操做的一種好方法是,在更改代碼前先編寫新的測試。這種開發方式成爲 測試驅動開發,能夠應用於整個項目或者是單個的補丁。在編寫測試後,運行這些測試以確保他們執行失敗(由於這裏尚未修復bug或者添加新的功能)。若是新的測試執行時沒有失敗,那就須要對他們進行修復以便他們執行正確,畢竟,不管是否存在錯誤,都會經過迴歸測試來測試,這對防止錯誤的出現很是有幫助。
下面的例子咱們親自動手實現。

爲工單 #24788 編寫測試

工單#24788提出了添加一個小功能:可以在Form類上指定類級別屬性prefix。

[...]與app一塊兒提供的表單能夠有效的命名本身,這樣N個重疊的表單字段能夠當即發佈並解析爲正確形式。

爲了解決這個工單,咱們須要爲BaseForm類添加一個prefix屬性,當建立這個類的實例時,把一個前綴傳遞給__init__()方法,會把這個前綴設置到建立的實例上。但不傳遞前綴(或者傳遞的是None)則會使用類級淺灰。在咱們作更改以前,咱們會寫幾個測試驗證咱們的修改是正常的,且在將來也能夠正常工做。

進入Django的tests/forms_tests/tests/目錄,打開test_forms.py文件。在test_forms_with_null_boolean函數以前的1674行加入如下代碼:

def test_class_prefix(self):
    # Prefix can be also specified at the class level.
    class Person(Form):
        first_name = CharField()
        prefix = 'foo'

    p = Person()
    self.assertEqual(p.prefix, 'foo')

    p = Person(prefix='bar')
    self.assertEqual(p.prefix, 'bar')

這個測試用於檢查設置的類級別前綴是否按預期工做,而且在建立實例時,傳遞prefix參數人就可用。

這個測試看起來可能有些難
若是你沒有編寫過測試,乍一看,感受會有點難寫。幸運的是,在計算機編程中,測試是一個很是大的概念,所以有不少相關的內容:

  • 爲Django編寫的測試的第一個好的介紹能夠在編寫和運行測試的文檔中找到。
  • Dive Into Python(一個免費的在線書籍,適合初學python的開發者)包含了精彩的 單元測試介紹
  • 讀完這些內容後,若是你還想了解更多的內容,那麼還有Python的 unittest 文檔。

運行新的測試

記住,咱們還麼有對BaseForm作任何修改,全部咱們的測試會失敗。咱們在forms_tests目錄中運行全部的測試,確保全部的測試都實際執行了。在命令行中,cd進Django的 tests/目錄,並運行下面的命令:

$ ./runtests.py forms_tests

若是測試運行正確,你應該能夠看到與咱們添加的測試對應的一個失敗。若是全部的測試都經過了,那麼你須要確保將以前的新測試添加到相應的目錄和文件中。

爲你的工單編寫代碼

接下來,咱們將把工單 #24788中描述的功能添加到Django。

爲工單 #24788 編寫代碼

進入django/django/forms/目錄,並打開forms.py文件。找到72上的 BaseForm類,在field_order屬性以後添加prefix類屬性。

class BaseForm:
    # This is the main implementation of all the Form logic. Note that this
    # class is different than Form. See the comments by the Form class for
    # more information. Any improvements to the form API should be made to
    # *this* class, not to the Form class.
    field_order = None
    prefix = None

驗證測試經過

當你完成了django的修改,就須要確保以前編寫的測試經過,這樣咱們就能夠看到上面編寫的代碼是否工做正常。在forms_tests目錄中運行測試,cd到django的tests/目錄,並運行下面的命令:

$ ./runtests.py forms_tests

糟糕,幸好咱們編寫了測試。你應該能夠看到相似下面異常的一個失敗:

AssertionError: None != 'foo'

咱們忘記了在 init 方法中添加條件判斷語句。修改django/forms/forms.py中的87行爲self.prefix = prefix,添加條件語句:

if prefix is not None:
    self.prefix = prefix

從新運行測試,全部的測試應該都會經過。若是沒有,確保你像前面展現的同樣正確的修改了BaseForm類,並正確複製了新測試。

第二次運行Django的測試套件

當你驗證了你的補丁和測試能夠正常工做後,最好運行django的整個測試組件來檢查你作的更改是否把其餘bug引入了django的其餘區域。雖然整個測試組件經過測試不表明你的代碼沒有問題,但它有助於檢查出許多被忽視的bug。

cd進入Django的tests/目錄,運行django的整個測試組件:

$ ./runtests.py

只要沒有看到失敗信息,就能夠繼續後面的內容了。

編寫文檔

這是一個新功能,所以應該記錄到文檔中,在django/docs/ref/forms/api.txt:文件中的1068行(文件的底部)添加下面的內容:

The prefix can also be specified on the form class::

    >>> class PersonForm(forms.Form):
    ...     ...
    ...     prefix = 'person'

.. versionadded:: 1.9

    The ability to specify ``prefix`` on the form class was added.

因爲這個新功能會出如今即將發佈的新版本中,由於它會被添加到 Django1.9的發佈說明中,位置在docs/releases/1.9.txt文件的164行,關於「Forms」的部分。

  • 能夠在form類中指定表單前綴,而不只僅是在實例化form時,更多信息請參閱:ref:form-prefix

有關編寫文檔的更多信息,包括有關版本versionadded的說明,請參閱https://docs.djangoproject.com/en/2.0/internals/contributing/writing-documentation/。這個頁面也包含如何構建文檔的一個本地副本,以便你能夠預覽以後要生成的HTML。

預覽更改

如今是時候完成補丁中全部的更改了。要心事當前django副本(包含你作的修改的)與本教程以前檢出的修訂版本之間的差別,執行下面的命令:

$ git diff

使用箭頭鍵進行上下查看:

diff --git a/django/forms/forms.py b/django/forms/forms.py
index 509709f..d1370de 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -75,6 +75,7 @@ class BaseForm:
     # information. Any improvements to the form API should be made to *this*
     # class, not to the Form class.
     field_order = None
+    prefix = None

     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                  initial=None, error_class=ErrorList, label_suffix=None,
@@ -83,7 +84,8 @@ class BaseForm:
         self.data = data or {}
         self.files = files or {}
         self.auto_id = auto_id
-        self.prefix = prefix
+        if prefix is not None:
+            self.prefix = prefix
         self.initial = initial or {}
         self.error_class = error_class
         # Translators: This is the default suffix added to form field labels
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 3bc39cd..008170d 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -1065,3 +1065,13 @@ You can put several Django forms inside one ``<form>`` tag. To give each
     >>> print(father.as_ul())
     <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
     <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
+
+The prefix can also be specified on the form class::
+
+    >>> class PersonForm(forms.Form):
+    ...     ...
+    ...     prefix = 'person'
+
+.. versionadded:: 1.9
+
+    The ability to specify ``prefix`` on the form class was added.
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 5b58f79..f9bb9de 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -161,6 +161,9 @@ Forms
   :attr:`~django.forms.Form.field_order` attribute, the ``field_order``
   constructor argument , or the :meth:`~django.forms.Form.order_fields` method.

+* A form prefix can be specified inside a form class, not only when
+  instantiating a form. See :ref:`form-prefix` for details.
+
 Generic Views
 ^^^^^^^^^^^^^

diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 690f205..e07fae2 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -1671,6 +1671,18 @@ class FormsTestCase(SimpleTestCase):
         self.assertEqual(p.cleaned_data['last_name'], 'Lennon')
         self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))

+    def test_class_prefix(self):
+        # Prefix can be also specified at the class level.
+        class Person(Form):
+            first_name = CharField()
+            prefix = 'foo'
+
+        p = Person()
+        self.assertEqual(p.prefix, 'foo')
+
+        p = Person(prefix='bar')
+        self.assertEqual(p.prefix, 'bar')
+
     def test_forms_with_null_boolean(self):
         # NullBooleanField is a bit of a special case because its presentation (widget)
         # is different than its data. This is handled transparently, though.

完成預覽修補後,按q鍵返回命令行。若是補丁的內容看起來沒問題,那麼是時候提交更改了。

提交修改

執行如下命令以提交修改:

$ git commit -a

執行該命令會打開一個文本編輯器以輸入提交信息,按照信息提交規則寫入相似於下面的信息:

Fixed #24788 -- Allowed Forms to specify a prefix at the class level.

推送提交併提交拉取請求

提交補丁後,將其發送到github上的fork(若是不同,可使用你的分支名代替「ticket_24788):

$ git push origin ticket_24788

你能夠經過訪問Django GitHub頁面來建立一個拉取請求。你會在「Your recently pushed branches」下看到你的分支,點擊它旁邊的「Compare & pull request」 。

在本教程範圍內,你不要執行該操做,但在下個頁面會顯示補丁的預覽,你能夠點擊 「Create pull request」。

下一步

祝賀你,你已經學會了向Django發送pull請求。更多高級技巧的信息能夠查看使用Git和GitHub工做

如今你能夠經過幫助django改進代碼庫來充分使用這些技巧。

有關貢獻者的貢多信息

在你開始爲django編寫補丁前,還有一些關於貢獻者的內容須要你瞭解一下:

  • 你應確保你已經閱讀了django文檔中認領工單和提交補丁的部分,。它涵蓋了Trac規則(Trac是一個軟件),如何認領工單、補丁的代碼風格,和許多其餘重要細節。
  • 第一次貢獻代碼的時候也應該閱讀django中關於第一次貢獻代碼的文檔。對於剛接觸django的新人來講,它有許多很好的建議。
  • 以後,若是你但願瞭解更多關於貢獻者的信息,你也能夠查看django文檔中關於貢獻的其他部分。這裏包含大量有用的信息,應該是解答你的問題的第一手資料。

找出你的第一個工單

當你查看了上面提到的內容後,就能夠去找一個工單來編寫補丁了。特別要注意哪些「easy pickings」工單。這些工單很是簡單,很是適合初次參與的貢獻者。當你熟悉瞭如何向Django提交貢獻,你就能夠改而解決更復雜困難的工單。

若是你只是想了解一下,請查看須要打補丁的簡單工單須要該進的補丁的工單。若是你熟悉編寫測試,你能夠查看須要測試的簡單工單。請記得遵循關於認領工單的知道原則,這些工單是在django文檔
請記得認領工單和提交補丁中,關於遵循Django文檔連接中提到的認領工單的指導原則。

建立pull請求後作什麼?

工單有補丁後,須要經過經過第二組人來進行審查。提交pull請求後,經過將工單上的標誌設置爲 「has patch」、「doesn’t need tests」等,來更新故障單的元數據。以便其餘人來查看。貢獻不表明要從頭開始編寫補丁。查看現有的補丁也是一項頗有用的貢獻,詳細信息能夠查看工單分類

相關文章
相關標籤/搜索