Заинтересованы в небольшой обратной помощи сообществу? Может быть Вы нашли ошибку в Django, которую хотели бы видеть исправленной, либо имеете небольшое новшество, которое хотели бы добавить.
Обратное содействие в Django - сам по себе лучший способ увидеть внутренние проблемы. Это может показаться сложным на первый взгляд, но это действительно довольно просто. Мы проведем Вас через весь процесс так, что Вы сможете научиться на этом примере.
См.также
Если вам нужна инструкция как отправлять патчи, смотрите Submitting patches.
Для этого учебника мы ожидаем, что у Вас, по крайней мере, есть общее понимание того, как Django работает. Это означает, что Вы должны комфортно пройти через существующее руководство по написанию Вашего первого приложения Django. Кроме того, Вы должны хорошо понимать сам Python. Но, если нет, то Dive Into Python - это прекрасная (и свободная) онлайн-книга для начинающих Python-программистов.
Те из вас, кто незнаком с системами контроля версий и Trac, увидят, что этот учебник и его ссылки содержат достаточно информации, чтобы начать работу. Впрочем, Вы, вероятно, захотите узнать больше об этих различных инструментах, если планируете содействовать Django постоянно.
По большей части правда, что этот учебник старается объяснить столько, насколько он может быть полезным для самой широкой аудитории.
Где получить помощь:
Если у Вас возникли проблемы с данным руководством, пожалуйста, отправьте сообщение на django-developers или посетите канал #django-dev на irc.freenode.net , чтобы пообщаться с другими пользователями Django, которые могут быть в состоянии помочь.
Мы будем двигаться к Вашему пониманию того, как отсылать патч для Django в первый раз. К концу этого урока Вы должны будете иметь базовое понимание как инструментов, так и связанных процессов. В частности, рассмотрим следующее:
Установка Git.
Как скачать разрабатываемую копию Django.
Запуск коллекции тестов Django.
Написание теста для патча.
Написание кода для патча.
Тестирование Вашего патча.
Создание файла патча для сделанных изменений.
Где искать дополнительные сведения.
Как только Вы закончите с учебником, то можете полистать напоследок Django-документацию по содействию. Материал содержит много полезной информации и является обязательным для прочтения всем, кто хотел бы стать постоянным автором Django. Если у вас остались вопросы, наверняка, там есть на них ответы.
Python 3 required!
This tutorial assumes you are using Python 3. Get the latest version at Python’s download page or with your operating system’s package manager.
For Windows users
When installing Python on Windows, make sure you check the option “Add python.exe to Path”, so that it is always available on the command line.
As a contributor, you can help us keep the Django community open and inclusive. Please read and follow our Code of Conduct.
Для этого урока Вам потребуется установить git, чтобы загрузить текущую разрабатываемую версию Django, а также для создания патч-файлов Ваших изменений.
Чтобы проверить, доступен ли git или Вы ещё не устанавливали его, введите git в командной строке. Если Вы получите сообщение о том, что эта команда не может быть найдена, Вам придется скачать и установить его, см. страницу скачивания Git.
For Windows users
When installing Git on Windows, it is recommended that you pick the “Git Bash” option so that Git runs in its own shell. This tutorial assumes that’s how you have installed it.
Если Вы не знакомы с git, то всегда можете узнать подробнее о командах (после его установки) путем ввода git help в командной строке.
Первым шагом для содействия Django, является получение копии исходного кода. Используйте команду cd в командной строке для перехода в каталог туда, куда думаете расположить Вашу локальную копию Django.
Download the Django source code repository using the following command:
$ git clone https://github.com/django/django.git
Now that you have a local copy of Django, you can install it just like you would install any package using pip. The most convenient way to do so is by using a virtual environment (or virtualenv) which is a feature built into Python that allows you to keep a separate directory of installed packages for each of your projects so that they don’t interfere with each other.
It’s a good idea to keep all your virtualenvs in one place, for example in .virtualenvs/ in your home directory. Create it if it doesn’t exist yet:
$ mkdir ~/.virtualenvs
Now create a new virtualenv by running:
$ python3 -m venv ~/.virtualenvs/djangodev
The path is where the new environment will be saved on your computer.
For Windows users
Using the built-in venv module will not work if you are also using the Git Bash shell on Windows, since activation scripts are only created for the system shell (.bat) and PowerShell (.ps1). Use the virtualenv package instead:
$ pip install virtualenv
$ virtualenv ~/.virtualenvs/djangodev
For Ubuntu users
Скачать исходный код репозитория Django можно используя следующую команду:
$ 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
The final step in setting up your virtualenv is to activate it:
$ source ~/.virtualenvs/djangodev/bin/activate
If the source command is not available, you can try using a dot instead:
$ . ~/.virtualenvs/djangodev/bin/activate
For Windows users
To activate your virtualenv on Windows, run:
$ source ~/virtualenvs/djangodev/Scripts/activate
You have to activate the virtualenv whenever you open a new terminal window. virtualenvwrapper__ is a useful tool for making this more convenient.
Anything you install through pip from now on will be installed in your new virtualenv, isolated from other environments and system-wide packages. Also, the name of the currently activated virtualenv is displayed on the command line to help you keep track of which one you are using. Go ahead and install the previously cloned copy of Django:
$ pip install -e /path/to/your/local/clone/django/
(где django - это каталог Вашего клона, содержащий setup.py) чтобы сделать ссылку на копию в виртуальном окружении. Это отличный вариант, чтобы изолировать разработку копии Django от остальной части Вашей системы и позволит избежать потенциальных конфликтов пакетов.
Для этого урока мы будем использовать тикет #17549 как учебное исследование, поэтому мы отмотаем назад историю Django версий в git, до того, как патч тикета был применён. Это позволит нам пройти через все этапы написания патча с нуля, включая запуск коллекции тестов Django.
Имейте в виду, что на данный момент, ниже, мы будем использовать более старую ревизию Django для учебных целей, но Вы должны будете всегда использовать текущую разрабатываемую версию Django при работе над своим собственным патчем тикета!
Примечание
Патч для этого тикета был написан Ульрихом Петри, и был применён в Django как `коммит ac2052ebc84c45709ab5f0f25e685bf656ce79bc`__. Следовательно, мы будем использовать ревизию Django просто до `коммита 39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac`__.
Перейдите в корневой каталог Django (это тот, который содержит django, docs, tests, AUTHORS и т.п.). Вы сможете потом проверить на старой ревизии Django, что же мы будем использовать в уроке ниже:
$ git checkout 4ccfc4439a7add24f8db4ef3960d02ef8ae09887
При внесении изменений непосредственно в Django, очень важно, чтобы ваш код с изменениями не вызывал ошибок в других областях Django. Один из способов убедиться в том, что Django по-прежнему работает после внесения изменений - запустить коллекцию тестов Django. Пока все тесты проходят, Вы можете быть уверены, что Ваши изменения ещё не разрушают целостность Django. Если Вы до этого никогда не запускали коллекцию тестов Django, то будет хорошей идеей, чтобы запустить их всего один раз, чтобы заранее ознакомиться с тем, как должен выглядеть их вывод.
Если вы используете Windows, то обозначенное выше должно работать при условии, что вы используете “Git Bash”, предоставляемый по-умолчанию при установке Git. На GitHub есть `прекрасное руководство`__.
$ pip install -r requirements/py3.txt
Если Вы используете virtualenv, то можно опустить PYTHONPATH=.. при выполнении тестов. Инструкции Python будут отыскивать Django в родительской директории каталога tests. virtualenv получает Вашу копию Django на PYTHONPATH автоматически.
$ ./runtests.py
Теперь посидите сложа руки и расслабьтесь. Весь набор тестов Django имеет более 4800 различных проверок, так что, это может занять от 5 до 15 минут, в зависимости от скорости Вашего компьютера.
Пока тесты Django выполняются, Вы увидите поток символов, представляющих состояние каждого теста, который выполняется в данный момент. E указывает, что произошла ошибка во время тестирования, а F указывает на то, что тест не прошёл по утверждениям одинаковости. Оба они считаются неудачными испытаниями. Между тем, x и s указывают на ожидаемые неудачи и пропущенные тесты соответственно. Точки показывают прохождение тестов.
Пропускаются тесты, как правило, из-за отсутствия внешних библиотек, необходимых для его запуска; см. Running all the tests для получения списка зависимостей и обязательно установите всё для тестов, связанных с изменениями, которые Вы делаете (сейчас нам не нужны никакие для этого учебника).
Когда тестирование завершится, Вы должны будете увидеть приветственное сообщение, уведомляющее о том, пройдены тесты, либо они провалились. Поскольку Вы ещё не сделали каких либо изменений в коде Django, то всё тестирование должно быть успешным. Если Вы получаете отказы или ошибки, убедитесь в том, что выполнили предыдущие шаги правильно. См. Running the unit tests для получения дополнительной информации.
Заметьте, что последняя ревизия основной ветки Django не всегда может быть стабильной. Во время разработки в эту ветку, Вы можете проверить `непрерывное интегрированное построение Django`__ чтобы определить, являются ли сбои специфичными для Вашей машины, или они также присутствуют в официальной сборке Django. Если Вы щёлкните на просмотр конкретной сборки, то сможете увидеть “Матрицу Конфигураций”, которая отображает сбои для версий Python и бэкендов баз данных.
Примечание
Для данного руководства и этого тикета, над которым мы работаем, тестирование с SQLite является достаточным, однако, можно (и иногда нужно) сделать запуск тестов с использованием различных баз данных.
В большинстве случаев, патч, который будет принят в Django, должен включать тесты. Для патчей, исправляющих ошибки, это означает написание регрессионного тестирования, чтобы гарантировать, что ошибка никогда больше не будет восстановлена в Django. Регрессионный тест должен быть написан таким образом, чтобы он не мог быть выполнен, пока ошибка существует и пройден после того, как ошибка была исправлена. Для патчей, содержащих новые возможности, Вам необходимо включить тесты, которые гарантируют, что эти новые возможности работают правильно. Они тоже должны завершаться ошибкой, когда новая возможность отсутствует, а затем проходить успешно, после её реализации.
Хороший способ сделать это, во-первых, писать новые тесты перед внесением любых изменений в код. Этот тип разработки называется `разработкой через тестирование`__ и может быть применена как к целым проектам, так и к отдельным патчам. После написания тестов, Вам нужно запустить их, чтобы убедиться, что они действительно проваливаются (ведь Вы еще не починили баг или не добавили эту возможность). Если Ваши новые тесты не проваливаются, то необходимо исправить их так, чтобы они это делали. Ведь, регрессионный тест, который проходит независимо от присутствия ошибки - не очень полезная вещь для предотвращения повторения этой ошибки в будущем.
Теперь за наш практический пример.
It’s useful for URLField to give you a way to open the URL; otherwise you might as well use a CharField (перевод: “Это полезно для URLField, чтобы дать Вам способ открыть URL-адрес; в противном случае также можно использовать CharField”).
[…] forms which ship with apps could effectively namespace themselves such
that N overlapping form fields could be POSTed at once and resolved to the
correct form.
В целях решения этого тикета, мы добавим метод render для AdminURLFieldWidget в целях отображения активной ссылки над виджетом ввода. Прежде чем мы примем эти изменения, мы собираемся написать пару тестов, чтобы убедиться, что наши модифицированные функции верны и продолжат правильно функционировать в будущем.
Перейдите в Django-каталог tests/regressiontests/admin_widgets/ и откройте файл tests.py. Добавьте следующий код на строке 269 непосредственно перед классом AdminFileWidgetTest:
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')
Проверьте новые тесты, чтобы увидеть, что метод render, который мы будем добавлять, корректно работает в нескольких различных ситуациях.
Но вся эта суть тестирования выглядит сложновато...
Если Вы никогда не имели дело с тестами прежде, они могут выглядеть на первый взгляд немного сложными в написании. К счастью, тестирование - это очень большая тема в компьютерном программировании, поэтому есть много различной информации:
Хороший первый взгляд на написание тестов для Django можно найти в документации на Создание и запуск тестов.
Погружение в Python (бесплатная онлайн-книга для начинающих Python-разработчиков) включает в себя великолепное `Введение в модульное тестирование`__.
После прочтения всего, если Вы захотите чего-то немного посерьёзнее, чтобы “погрызть”, всегда есть `документация на unittest в Python`__.
Запомните, что мы фактически не делали изменений в файле AdminURLFieldWidget, так что наши тесты провалятся. Давайте запустим все тесты из model_forms_regress, чтобы убедиться, что это действительно то, что должно происходить. В командной строке, командой cd перейдите в Django-директорию tests/ и запустите:
$ ./runtests.py forms_tests
Если тесты выполнены правильно, Вы должны увидеть три неудачи, соответствующие каждому из методов испытаний, которые мы добавляли. Если все тесты прошли, то Вы должны удостовериться, что добавили новый тест именно так, как показано выше, в соответствующую папку и класс.
Далее мы будем добавлять в Django функциональность, описанную в тикете #17549.
Перейдите в папку django/django/contrib/admin/ и откройте файл widgets.py. Найдите класс AdminURLFieldWidget на строке 302 и добавьте следующий метод render после существующего метода __init__:
class BaseForm(object):
# 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, то должны убедиться в том, что тесты, которые мы с Вами писали ранее, пройдут так, чтобы можно было увидеть, работает ли правильно код, написанный выше. Чтобы запустить тесты из папки admin_widgets, скомандуйте cd в Django-директорию tests/ и запустите:
$ ./runtests.py forms_tests
Ой, как хорошо, что мы написали эти тесты! Вы все равно должны увидеть 3 неудачи со следующим исключением:
AssertionError: None != 'foo'
Мы забыли добавить, что нужно импортировать для метода. Идём дальше, и добавляем импорт smart_urlquote в конце линии 13 в файле django/contrib/admin/widgets.py, чтобы она выглядела следующим образом:
if prefix is not None:
self.prefix = prefix
Повторный запустите тесты и все должно пройти. Если этого не произошло, убедитесь, что правильно изменили класс AdminURLFieldWidget так, как показано выше, и правильно скопируйте новые тесты.
Как только Вы убедились, что Ваш патч и тестирование работают правильно, будет хорошей идеей запуск всего набора Django-тестов просто для того, чтобы убедиться, что Ваши изменения не внесли какие-либо ошибки в другие области Django. А успешное прохождение всего набора тестов гарантированно не даст, чтобы код свободно делал ошибки, оно помогает выявить множество багов и регрессий, которые иначе могли бы остаться незамеченными.
Чтобы запустить весь набор тестов Джанго, скомандуйте cd в Django-директорию tests/ и запустите:
$ ./runtests.py
Пока Вы не видите каких-либо сбоев, всё идёт хорошо. Обратите внимание, что это исправление также сделало `небольшое CSS изменение`__ чтобы отформатировать новый виджет. Вы можете внести аналогичные, если хочется, но мы пропустим это сейчас в интересах краткости.
This is a new feature, so it should be documented. Add the following section on line 1068 (at the end of the file) of django/docs/ref/forms/api.txt:
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.
Это новая возможность, поэтому она должна быть задокументирована. Добавьте следующий текст на строке 925 в django/docs/ref/models/fields.txt под существующую документацию к URLField:
* A form prefix can be specified inside a form class, not only when
instantiating a form. See :ref:`form-prefix` for details.
Для более подробной информации о написании документации, в том числе объяснению того, что такое versionadded, см. Writing documentation. Эта страница также включает объяснение о том, как построить копию документации локально так, чтобы Вы могли просматривать сгенерированный HTML-код.
Теперь пришло время для создания патч-файлов, которые могут быть загружены в Trac, либо применены к другой копии Django. Чтобы взглянуть на содержимое Вашего патча, выполните следующую команду:
$ git diff
Это будет отображать разницу между текущей копией Django (с Вашими изменениями) и той ревизией, с которой Вы изначально начали ранее в этом учебнике.
Как только закончите любоваться патчем, нажмите клавишу q для возврата обратно в командную строку. Если контент патча выглядел хорошо, то можете запустить следующую команду, которая сохранит патч-файл текущего рабочего каталога:
$ git diff > 24788.diff
Теперь Вы должны иметь файл в корневом каталоге Django, с именем 17549.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(object):
# 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(object):
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.
Поздравляем, Вы создали свой самый первый Django-патч! Теперь, когда Вы знаете, “что у зайчика внутри”, то можете направить эти навыки для более хорошего применения, помогая улучшить кодовую базу Django. Генерация патчей и прикрепление их к трекеру тикетов полезна, однако, поскольку мы используем git - рекомендуем сильнее адаптироваться к рабочему процессу, ориентированному на git.
Поскольку мы никогда не коммитили наши изменения локально, выполните следующее, чтобы вернуть вашу ветку git обратно, к хорошей отправной точке:
$ git reset --hard HEAD
$ git checkout master
Прежде чем Вы приступите к написанию следующих патчей для Django, имеется немного больше информации для участников, и Вам, вероятно, следует взглянуть на:
Вы должны обязательно прочитать Django-документацию об утверждении тикетов и принятии патчей. Она охватывает правила этикета в Trac, получение тикетов для себя, ожидаемый стиль кодирования для патчей, и многие другие важные детали.
Новые участники также должны прочитать Django-документацию для новых вкладчиков. Оно имеет множество хороших советов от тех из нас, кто уже помогал Django.
После этого, если Вас всё еще будет мучить жажда получения дополнительных сведений о вкладе в Django, то Вы всегда можете просмотреть остальную Django-документацию по содействию. Она содержит массу полезной информации и должна стать Вашим первым источником для ответов на любые возникшие вопросы.
После того как Вы постигните некоторую информацию, станете готовы к самостоятельному поиску тикета, чтобы написать патч для него. Обратите особое внимание на тикеты с критерием “easy pickings”. Эти задачи, как правило, гораздо проще по своей природе и великолепно подходят для новоиспечённых вкладчиков. Когда Вы поближе познакомитесь с контрибуцией в Django, то можете переходить к написанию патчей для более трудных и сложных тикетов.
Если Вы просто хотите начать работу сейчас (и никто не будет Вас в этом винить!), то попробуйте взглянуть на списки `простых тикетов, которым нужны патчи`__ и `простых тикетов, у которых есть патчи, нуждающиеся в улучшении`__. Если Вы знакомы с написанием тестов, то можете также взглянуть на список `простые тикеты, которым нужны тесты`__. Только не забывайте следовать рекомендациям, упомянутым в ссылке Django-документации об утверждении тикетов и принятии патчей о том, как зарезервировать тикеты.
После того, как тикет был запатчен, он должен быть рассмотрен посторонним взглядом. После загрузки патча или его отправки, не забудьте обновить метаданные тикета путем установки флагов “has patch”, “doesn’t need tests” и т. д., чтобы другие могли найти его для обзора. Вклад не обязательно всегда означает написание патча с нуля. Анализ существующих патчей тоже очень полезный вклад. См. подробнее Triaging tickets.
Mar 31, 2016