Fixed #24907 -- Updated contributing tutorial with a more recent example ticket.

This commit is contained in:
Markus Amalthea Magnuson 2015-06-05 01:06:03 +01:00 committed by Tim Graham
parent 7abf418eb1
commit 3fd754f12d
2 changed files with 205 additions and 200 deletions

View File

@ -97,15 +97,19 @@ The first step to contributing to Django is to get a copy of the source code.
From the command line, use the ``cd`` command to navigate to the directory From the command line, use the ``cd`` command to navigate to the directory
where you'll want your local copy of Django to live. where you'll want your local copy of Django to live.
Download the Django source code repository using the following command:: Download the Django source code repository using the following command:
git clone https://github.com/django/django.git .. code-block:: console
$ git clone https://github.com/django/django.git
.. note:: .. note::
For users who wish to use `virtualenv`__, you can use:: For users who wish to use `virtualenv`__, you can use:
pip install -e /path/to/your/local/clone/django/ .. code-block:: console
$ pip install -e /path/to/your/local/clone/django/
(where ``django`` is the directory of your clone that contains (where ``django`` is the directory of your clone that contains
``setup.py``) to link your cloned checkout into a virtual environment. This ``setup.py``) to link your cloned checkout into a virtual environment. This
@ -117,7 +121,7 @@ __ http://www.virtualenv.org
Rolling back to a previous revision of Django Rolling back to a previous revision of Django
============================================= =============================================
For this tutorial, we'll be using ticket :ticket:`17549` as a case study, so we'll For this tutorial, we'll be using ticket :ticket:`24788` as a case study, so we'll
rewind Django's version history in git to before that ticket's patch was rewind Django's version history in git to before that ticket's patch was
applied. This will allow us to go through all of the steps involved in writing applied. This will allow us to go through all of the steps involved in writing
that patch from scratch, including running Django's test suite. that patch from scratch, including running Django's test suite.
@ -128,36 +132,46 @@ development revision of Django when working on your own patch for a ticket!**
.. note:: .. note::
The patch for this ticket was written by Ulrich Petri, and it was applied The patch for this ticket was written by Paweł Marczewski, and it was
to Django as `commit ac2052ebc84c45709ab5f0f25e685bf656ce79bc`__. applied to Django as `commit 4df7e8483b2679fc1cba3410f08960bac6f51115`__.
Consequently, we'll be using the revision of Django just prior to that, Consequently, we'll be using the revision of Django just prior to that,
`commit 39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac`__. `commit 4ccfc4439a7add24f8db4ef3960d02ef8ae09887`__.
__ https://github.com/django/django/commit/ac2052ebc84c45709ab5f0f25e685bf656ce79bc __ https://github.com/django/django/commit/4df7e8483b2679fc1cba3410f08960bac6f51115
__ https://github.com/django/django/commit/39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac __ https://github.com/django/django/commit/4ccfc4439a7add24f8db4ef3960d02ef8ae09887
Navigate into Django's root directory (that's the one that contains ``django``, Navigate into Django's root directory (that's the one that contains ``django``,
``docs``, ``tests``, ``AUTHORS``, etc.). You can then check out the older ``docs``, ``tests``, ``AUTHORS``, etc.). You can then check out the older
revision of Django that we'll be using in the tutorial below:: revision of Django that we'll be using in the tutorial below:
git checkout 39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac .. code-block:: console
$ git checkout 4ccfc4439a7add24f8db4ef3960d02ef8ae09887
Running Django's test suite for the first time Running Django's test suite for the first time
============================================== ==============================================
When contributing to Django it's very important that your code changes don't When contributing to Django it's very important that your code changes don't
introduce bugs into other areas of Django. One way to check that Django still introduce bugs into other areas of Django. One way to check that Django still
works after you make your changes is by running Django's test suite. If all works after you make your changes is by running Django's test suite. If all
the tests still pass, then you can be reasonably sure that your changes the tests still pass, then you can be reasonably sure that your changes
haven't completely broken Django. If you've never run Django's test suite haven't completely broken Django. If you've never run Django's test suite
before, it's a good idea to run it once beforehand just to get familiar with before, it's a good idea to run it once beforehand just to get familiar with
what its output is supposed to look like. what its output is supposed to look like.
We can run the test suite by simply ``cd``-ing into the Django ``tests/`` Before running the test suite, install its dependencies by first ``cd``-ing
directory and, if you're using GNU/Linux, Mac OS X or some other flavor of into the Django ``tests/`` directory and then running:
Unix, run::
PYTHONPATH=.. python runtests.py --settings=test_sqlite .. code-block:: console
$ pip install -r requirements/py3.txt # or py2.txt if you are running Python 2
Now we are ready to run the test suite. If you're using GNU/Linux, Mac OS X or
some other flavor of Unix, run:
.. code-block:: console
$ PYTHONPATH=.. ./runtests.py
If you're on Windows, the above should work provided that you are using If you're on Windows, the above should work provided that you are using
"Git Bash" provided by the default Git install. GitHub has a `nice tutorial`__. "Git Bash" provided by the default Git install. GitHub has a `nice tutorial`__.
@ -171,7 +185,7 @@ __ https://help.github.com/articles/set-up-git#platform-windows
of ``tests``. ``virtualenv`` puts your copy of Django on the ``PYTHONPATH`` of ``tests``. ``virtualenv`` puts your copy of Django on the ``PYTHONPATH``
automatically. automatically.
Now sit back and relax. Django's entire test suite has over 4800 different Now sit back and relax. Django's entire test suite has over 9,600 different
tests, so it can take anywhere from 5 to 15 minutes to run, depending on the tests, so it can take anywhere from 5 to 15 minutes to run, depending on the
speed of your computer. speed of your computer.
@ -234,56 +248,42 @@ Now for our hands-on example.
__ http://en.wikipedia.org/wiki/Test-driven_development __ http://en.wikipedia.org/wiki/Test-driven_development
Writing some tests for ticket #17549 Writing some tests for ticket #24788
------------------------------------ ------------------------------------
Ticket :ticket:`17549` describes the following, small feature addition: Ticket :ticket:`24788` proposes a small feature addition: the ability to
specify the class level attribute ``prefix`` on Form classes, so that::
It's useful for URLField to give you a way to open the URL; otherwise you […] forms which ship with apps could effectively namespace themselves such
might as well use a CharField. that N overlapping form fields could be POSTed at once and resolved to the
correct form.
In order to resolve this ticket, we'll add a ``render`` method to the In order to resolve this ticket, we'll add a ``prefix`` attribute to the
``AdminURLFieldWidget`` in order to display a clickable link above the input ``BaseForm`` class. When creating instances of this class, passing a prefix to
widget. Before we make those changes though, we're going to write a couple the ``__init__()`` method will still set that prefix on the created instance.
tests to verify that our modification functions correctly and continues to But not passing a prefix (or passing ``None``) will use the class-level prefix.
function correctly in the future. Before we make those changes though, we're going to write a couple tests to
verify that our modification functions correctly and continues to function
correctly in the future.
Navigate to Django's ``tests/regressiontests/admin_widgets/`` folder and Navigate to Django's ``tests/forms_tests/tests/`` folder and open the
open the ``tests.py`` file. Add the following code on line 269 right before the ``test_forms.py`` file. Add the following code on line 1674 right before the
``AdminFileWidgetTest`` class:: ``test_forms_with_null_boolean`` function::
class AdminURLWidgetTest(DjangoTestCase): def test_class_prefix(self):
def test_render(self): # Prefix can be also specified at the class level.
w = widgets.AdminURLFieldWidget() class Person(Form):
self.assertHTMLEqual( first_name = CharField()
conditional_escape(w.render('test', '')), prefix = 'foo'
'<input class="vURLField" name="test" type="text" />'
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com')),
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /></p>'
)
def test_render_idn(self): p = Person()
w = widgets.AdminURLFieldWidget() self.assertEqual(p.prefix, 'foo')
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-äüö.com')),
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com" /></p>'
)
def test_render_quoting(self): p = Person(prefix='bar')
w = widgets.AdminURLFieldWidget() self.assertEqual(p.prefix, 'bar')
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com/<sometag>some text</sometag>')),
'<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some text</sometag>" /></p>'
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>')),
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
)
The new tests check to see that the ``render`` method we'll be adding works This new test checks that setting a class level prefix works as expected, and
correctly in a couple different situations. that passing a ``prefix`` parameter when creating an instance still works too.
.. admonition:: But this testing thing looks kinda hard... .. admonition:: But this testing thing looks kinda hard...
@ -304,68 +304,67 @@ __ https://docs.python.org/library/unittest.html
Running your new test Running your new test
--------------------- ---------------------
Remember that we haven't actually made any modifications to Remember that we haven't actually made any modifications to ``BaseForm`` yet,
``AdminURLFieldWidget`` yet, so our tests are going to fail. Let's run all the so our tests are going to fail. Let's run all the tests in the ``forms_tests``
tests in the ``model_forms_regress`` folder to make sure that's really what folder to make sure that's really what happens. From the command line, ``cd``
happens. From the command line, ``cd`` into the Django ``tests/`` directory into the Django ``tests/`` directory and run:
and run::
PYTHONPATH=.. python runtests.py --settings=test_sqlite admin_widgets .. code-block:: console
If the tests ran correctly, you should see three failures corresponding to each $ PYTHONPATH=.. ./runtests.py forms_tests
of the test methods we added. If all of the tests passed, then you'll want to
make sure that you added the new test shown above to the appropriate folder and If the tests ran correctly, you should see one failure corresponding to the test
class. method we added. If all of the tests passed, then you'll want to make sure that
you added the new test shown above to the appropriate folder and class.
Writing the code for your ticket Writing the code for your ticket
================================ ================================
Next we'll be adding the functionality described in ticket :ticket:`17549` to Next we'll be adding the functionality described in ticket :ticket:`24788` to
Django. Django.
Writing the code for ticket #17549 Writing the code for ticket #24788
---------------------------------- ----------------------------------
Navigate to the ``django/django/contrib/admin/`` folder and open the Navigate to the ``django/django/forms/`` folder and open the ``forms.py`` file.
``widgets.py`` file. Find the ``AdminURLFieldWidget`` class on line 302 and add Find the ``BaseForm`` class on line 72 and add the ``prefix`` class attribute
the following ``render`` method after the existing ``__init__`` method:: right after the ``field_order`` attribute::
def render(self, name, value, attrs=None): class BaseForm(object):
html = super(AdminURLFieldWidget, self).render(name, value, attrs) # This is the main implementation of all the Form logic. Note that this
if value: # class is different than Form. See the comments by the Form class for more
value = force_text(self._format_value(value)) # information. Any improvements to the form API should be made to *this*
final_attrs = {'href': mark_safe(smart_urlquote(value))} # class, not to the Form class.
html = format_html( field_order = None
'<p class="url">{} <a {}>{}</a><br />{} {}</p>', prefix = None
_('Currently:'), flatatt(final_attrs), value,
_('Change:'), html
)
return html
Verifying your test now passes Verifying your test now passes
------------------------------ ------------------------------
Once you're done modifying Django, we need to make sure that the tests we wrote Once you're done modifying Django, we need to make sure that the tests we wrote
earlier pass, so we can see whether the code we wrote above is working earlier pass, so we can see whether the code we wrote above is working
correctly. To run the tests in the ``admin_widgets`` folder, ``cd`` into the correctly. To run the tests in the ``forms_tests`` folder, ``cd`` into the
Django ``tests/`` directory and run:: Django ``tests/`` directory and run:
PYTHONPATH=.. python runtests.py --settings=test_sqlite admin_widgets .. code-block:: console
Oops, good thing we wrote those tests! You should still see 3 failures with $ PYTHONPATH=.. ./runtests.py forms_tests
Oops, good thing we wrote those tests! You should still see one failure with
the following exception:: the following exception::
NameError: global name 'smart_urlquote' is not defined AssertionError: None != 'foo'
We forgot to add the import for that method. Go ahead and add the We forgot to add the conditional statement in the ``__init__`` method. Go ahead
``smart_urlquote`` import at the end of line 13 of and change ``self.prefix = prefix`` that is now on line 87 of
``django/contrib/admin/widgets.py`` so it looks as follows:: ``django/forms/forms.py``, adding a conditional statement::
from django.utils.html import escape, format_html, format_html_join, smart_urlquote if prefix is not None:
self.prefix = prefix
Re-run the tests and everything should pass. If it doesn't, make sure you Re-run the tests and everything should pass. If it doesn't, make sure you
correctly modified the ``AdminURLFieldWidget`` class as shown above and correctly modified the ``BaseForm`` class as shown above and copied the new test
copied the new tests correctly. correctly.
Running Django's test suite for the second time Running Django's test suite for the second time
=============================================== ===============================================
@ -377,27 +376,36 @@ passing the entire test suite doesn't guarantee your code is bug free, it does
help identify many bugs and regressions that might otherwise go unnoticed. help identify many bugs and regressions that might otherwise go unnoticed.
To run the entire Django test suite, ``cd`` into the Django ``tests/`` To run the entire Django test suite, ``cd`` into the Django ``tests/``
directory and run:: directory and run:
PYTHONPATH=.. python runtests.py --settings=test_sqlite .. code-block:: console
As long as you don't see any failures, you're good to go. Note that this fix $ PYTHONPATH=.. ./runtests.py
also made a `small CSS change`__ to format the new widget. You can make the
change if you'd like, but we'll skip it for now in the interest of brevity.
__ https://github.com/django/django/commit/ac2052ebc84c45709ab5f0f25e685bf656ce79bc#diff-0 As long as you don't see any failures, you're good to go.
Writing Documentation Writing Documentation
===================== =====================
This is a new feature, so it should be documented. Add the following on line This is a new feature, so it should be documented. Add the following section on
925 of ``django/docs/ref/models/fields.txt`` beneath the existing docs for line 1068 (at the end of the file) of ``django/docs/ref/forms/api.txt``::
``URLField``::
.. versionadded:: 1.5 The prefix can also be specified on the form class::
The current value of the field will be displayed as a clickable link above the >>> class PersonForm(forms.Form):
input widget. ... ...
... prefix = 'person'
.. versionadded:: 1.9
The ability to specify ``prefix`` on the form class was added.
Since this new feature will be in an upcoming release it is also added to the
release notes for Django 1.9, on line 164 under the "Forms" section in the file
``docs/releases/1.9.txt``::
* A form prefix can be specified inside a form class, not only when
instantiating a form. See :ref:`form-prefix` for details.
For more information on writing documentation, including an explanation of what For more information on writing documentation, including an explanation of what
the ``versionadded`` bit is all about, see the ``versionadded`` bit is all about, see
@ -410,113 +418,106 @@ Generating a patch for your changes
Now it's time to generate a patch file that can be uploaded to Trac or applied Now it's time to generate a patch file that can be uploaded to Trac or applied
to another copy of Django. To get a look at the content of your patch, run the to another copy of Django. To get a look at the content of your patch, run the
following command:: following command:
git diff .. code-block:: console
$ git diff
This will display the differences between your current copy of Django (with This will display the differences between your current copy of Django (with
your changes) and the revision that you initially checked out earlier in the your changes) and the revision that you initially checked out earlier in the
tutorial. tutorial.
Once you're done looking at the patch, hit the ``q`` key to exit back to the Once you're done looking at the patch, hit the ``q`` key to exit back to the
command line. If the patch's content looked okay, you can run the following command line. If the patch's content looked okay, you can run the following
command to save the patch file to your current working directory:: command to save the patch file to your current working directory:
git diff > 17549.diff .. code-block:: console
You should now have a file in the root Django directory called ``17549.diff``. $ git diff > 24788.diff
You should now have a file in the root Django directory called ``24788.diff``.
This patch file contains all your changes and should look this: This patch file contains all your changes and should look this:
.. code-block:: diff .. code-block:: diff
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py diff --git a/django/forms/forms.py b/django/forms/forms.py
index 1e0bc2d..9e43a10 100644 index 509709f..d1370de 100644
--- a/django/contrib/admin/widgets.py --- a/django/forms/forms.py
+++ b/django/contrib/admin/widgets.py +++ b/django/forms/forms.py
@@ -10,7 +10,7 @@ from django.contrib.admin.templatetags.admin_static import static @@ -75,6 +75,7 @@ class BaseForm(object):
from django.core.urlresolvers import reverse # information. Any improvements to the form API should be made to *this*
from django.forms.widgets import RadioFieldRenderer # class, not to the Form class.
from django.forms.util import flatatt field_order = None
-from django.utils.html import escape, format_html, format_html_join + prefix = None
+from django.utils.html import escape, format_html, format_html_join, smart_urlquote
from django.utils.text import Truncator
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
@@ -306,6 +306,18 @@ class AdminURLFieldWidget(forms.TextInput):
final_attrs.update(attrs)
super(AdminURLFieldWidget, self).__init__(attrs=final_attrs)
+ def render(self, name, value, attrs=None): def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
+ html = super(AdminURLFieldWidget, self).render(name, value, attrs) initial=None, error_class=ErrorList, label_suffix=None,
+ if value: @@ -83,7 +84,8 @@ class BaseForm(object):
+ value = force_text(self._format_value(value)) self.data = data or {}
+ final_attrs = {'href': mark_safe(smart_urlquote(value))} self.files = files or {}
+ html = format_html( self.auto_id = auto_id
+ '<p class="url">{} <a {}>{}</a><br />{} {}</p>', - self.prefix = prefix
+ _('Currently:'), flatatt(final_attrs), value, + if prefix is not None:
+ _('Change:'), html + self.prefix = prefix
+ ) self.initial = initial or {}
+ return html 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>
+ +
class AdminIntegerFieldWidget(forms.TextInput): +The prefix can also be specified on the form class::
class_name = 'vIntegerField'
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index 809d56e..d44f85f 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -922,6 +922,10 @@ Like all :class:`CharField` subclasses, :class:`URLField` takes the optional
:attr:`~CharField.max_length`argument. If you don't specify
:attr:`~CharField.max_length`, a default of 200 is used.
+.. versionadded:: 1.5
+ +
+The current value of the field will be displayed as a clickable link above the + >>> class PersonForm(forms.Form):
+input widget. + ... ...
+ ... prefix = 'person'
Relationship fields
===================
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py
index 4b11543..94acc6d 100644
--- a/tests/regressiontests/admin_widgets/tests.py
+++ b/tests/regressiontests/admin_widgets/tests.py
@@ -265,6 +265,35 @@ class AdminSplitDateTimeWidgetTest(DjangoTestCase):
'<p class="datetime">Datum: <input value="01.12.2007" type="text" class="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" class="vTimeField" name="test_1" size="8" /></p>',
)
+class AdminURLWidgetTest(DjangoTestCase):
+ def test_render(self):
+ w = widgets.AdminURLFieldWidget()
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', '')),
+ '<input class="vURLField" name="test" type="text" />'
+ )
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example.com')),
+ '<p class="url">Currently:<a href="http://example.com">http://example.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /></p>'
+ )
+ +
+ def test_render_idn(self): +.. versionadded:: 1.9
+ w = widgets.AdminURLFieldWidget()
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example-äüö.com')),
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://example-äüö.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com" /></p>'
+ )
+ +
+ def test_render_quoting(self): + The ability to specify ``prefix`` on the form class was added.
+ w = widgets.AdminURLFieldWidget() diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
+ self.assertHTMLEqual( index 5b58f79..f9bb9de 100644
+ conditional_escape(w.render('test', 'http://example.com/<sometag>some text</sometag>')), --- a/docs/releases/1.9.txt
+ '<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some text</sometag>" /></p>' +++ b/docs/releases/1.9.txt
+ ) @@ -161,6 +161,9 @@ Forms
+ self.assertHTMLEqual( :attr:`~django.forms.Form.field_order` attribute, the ``field_order``
+ conditional_escape(w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>')), constructor argument , or the :meth:`~django.forms.Form.order_fields` method.
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E">http://example-äüö.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-äüö.com/<sometag>some text</sometag>" /></p>'
+ )
class AdminFileWidgetTest(DjangoTestCase): +* A form prefix can be specified inside a form class, not only when
def test_render(self): + 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.
So what do I do next? So what do I do next?
===================== =====================
@ -529,10 +530,12 @@ oriented workflow </internals/contributing/writing-code/working-with-git>` is
recommended. recommended.
Since we never committed our changes locally, perform the following to get your Since we never committed our changes locally, perform the following to get your
git branch back to a good starting point:: git branch back to a good starting point:
git reset --hard HEAD .. code-block:: console
git checkout master
$ git reset --hard HEAD
$ git checkout master
More information for new contributors More information for new contributors
------------------------------------- -------------------------------------
@ -561,7 +564,7 @@ Finding your first real ticket
Once you've looked through some of that information, you'll be ready to go out Once you've looked through some of that information, you'll be ready to go out
and find a ticket of your own to write a patch for. Pay special attention to and find a ticket of your own to write a patch for. Pay special attention to
tickets with the "easy pickings" criterion. These tickets are often much tickets with the "easy pickings" criterion. These tickets are often much
simpler in nature and are great for first time contributors. Once you're simpler in nature and are great for first time contributors. Once you're
familiar with contributing to Django, you can move on to writing patches for familiar with contributing to Django, you can move on to writing patches for
more difficult and complicated tickets. more difficult and complicated tickets.

View File

@ -455,6 +455,7 @@ makemessages
makemigrations makemigrations
Mako Mako
Mapnik Mapnik
Marczewski
Marino Marino
Markus Markus
MBR MBR
@ -545,6 +546,7 @@ Palau
parameterized parameterized
params params
parens parens
Paweł
pdf pdf
PEM PEM
perl perl