有興趣爲社區作一些貢獻?可能你發現了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編寫一個補丁,教程的最後,你應該對涉及的工具和流程有一個基本的理解。具體來講,咱們會涵蓋一下內容:數據庫
一旦你完成本教程,你就能夠學習剩下的 Django’s documentation on contributing了。它包含了大量信息,全部想變成django貢獻者的人都必須閱讀它。若是你遇到問題,它可能會給你答案。django
須要使用python3
當前版本的django再也不支持python2.7。去python下載頁或者你的操做系統的包管理器獲取python3。
windows用戶
在windows中安裝python時,去報你選中了「Add python.exe to Path」選項,這樣在命令行就老是有效的了編程
做爲一個貢獻者,你能夠幫助咱們保持django社區的開放性和包容性,請閱讀咱們的代碼規範
在本教程中,你須要安裝Git如下載django當前的開發版本,併爲你作的更改生成補丁文件。
檢查你是否已經安裝it,在命令行中輸入git
。若是你獲得的信息是找不到這個命令。你必須去下載並安裝它,請參閱 Git下載頁
windows用戶
在windows上安裝Git時,建議選擇「Git Bash」選項,這樣Git就會運行在它本身的shell中。本教程假定你已經安裝它。
若是你不熟悉Git,你能夠經過在命令行輸入git help
來找出更多關於它的命令。
爲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版本指向你的本地副本。你能夠馬上看到你對它作的任何更改,在你在第一個補丁的時候這會有對你很是大的幫助。
在本教程中,咱們將使用#24788來做爲學習用例,所以咱們須要把git中django的版本回滾到問題補丁沒有提交以前的版本。這會讓咱們參與進從頭開始編寫補丁的全部步驟中,包括正在運行的django測試組件。
請記住,雖然外面將在下面的教程中使用舊的django主幹版本,但在處理本身的補丁時,你應該始終使用django的當前開發版本
注意
這裏的補丁由Paweł Marczewski編寫,並已經應用於django,提交標記4df7e8483b2679fc1cba3410f08960bac6f51115,所以,咱們將使用在此以前的django版本,4ccfc4439a7add24f8db4ef3960d02ef8ae09887.
導航到djanmgo的根目錄(它是包含django, docs, tests, AUTHORS等的目錄)。你能夠檢出咱們將在下面的教程中使用的django的舊版本:
git checkout 4ccfc4439a7add24f8db4ef3960d02ef8ae09887
在爲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 表示測試的斷言失敗。這兩種狀況都被認爲是測試失敗。同時,x 和 s 分別表示預期的失敗和跳過的測試,圓點則表示測試經過。
跳過的測試一般是由於缺乏運行測試的外部庫;請檢查運行全部測試須要使用的依賴的列表,確保安裝了全部與你正在修改的相關的測試測全部依賴(本教程不須要額外安裝任何依賴)。一些特定的測試用於測試數據庫後端,若是不作後端測試,那麼就會被跳過。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提出了添加一個小功能:可以在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參數人就可用。
這個測試看起來可能有些難
若是你沒有編寫過測試,乍一看,感受會有點難寫。幸運的是,在計算機編程中,測試是一個很是大的概念,所以有不少相關的內容:
記住,咱們還麼有對BaseForm作任何修改,全部咱們的測試會失敗。咱們在forms_tests目錄中運行全部的測試,確保全部的測試都實際執行了。在命令行中,cd進Django的 tests/目錄,並運行下面的命令:
$ ./runtests.py forms_tests
若是測試運行正確,你應該能夠看到與咱們添加的測試對應的一個失敗。若是全部的測試都經過了,那麼你須要確保將以前的新測試添加到相應的目錄和文件中。
接下來,咱們將把工單 #24788中描述的功能添加到Django。
進入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的整個測試組件來檢查你作的更改是否把其餘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編寫補丁前,還有一些關於貢獻者的內容須要你瞭解一下:
當你查看了上面提到的內容後,就能夠去找一個工單來編寫補丁了。特別要注意哪些「easy pickings」工單。這些工單很是簡單,很是適合初次參與的貢獻者。當你熟悉瞭如何向Django提交貢獻,你就能夠改而解決更復雜困難的工單。
若是你只是想了解一下,請查看須要打補丁的簡單工單和須要該進的補丁的工單。若是你熟悉編寫測試,你能夠查看須要測試的簡單工單。請記得遵循關於認領工單的知道原則,這些工單是在django文檔
請記得認領工單和提交補丁中,關於遵循Django文檔連接中提到的認領工單的指導原則。
工單有補丁後,須要經過經過第二組人來進行審查。提交pull請求後,經過將工單上的標誌設置爲 「has patch」、「doesn’t need tests」等,來更新故障單的元數據。以便其餘人來查看。貢獻不表明要從頭開始編寫補丁。查看現有的補丁也是一項頗有用的貢獻,詳細信息能夠查看工單分類。