有兴趣为社区作一些贡献?可能你发现了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”等,来更新故障单的元数据。以便其余人来查看。贡献不表明要从头开始编写补丁。查看现有的补丁也是一项颇有用的贡献,详细信息能够查看工单分类。