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

相关文章
相关标签/搜索