summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/faq/contributing.txt2
-rw-r--r--docs/index.txt3
-rw-r--r--docs/internals/committers.txt43
-rw-r--r--docs/internals/deprecation.txt17
-rw-r--r--docs/intro/tutorial04.txt70
-rw-r--r--docs/intro/tutorial05.txt82
-rw-r--r--docs/ref/class-based-views/base.txt2
-rw-r--r--docs/ref/contrib/admin/admindocs.txt7
-rw-r--r--docs/ref/contrib/gis/forms-api.txt165
-rw-r--r--docs/ref/contrib/gis/index.txt1
-rw-r--r--docs/ref/contrib/gis/testing.txt57
-rw-r--r--docs/ref/django-admin.txt41
-rw-r--r--docs/ref/forms/fields.txt14
-rw-r--r--docs/ref/models/fields.txt3
-rw-r--r--docs/ref/models/querysets.txt4
-rw-r--r--docs/ref/settings.txt7
-rw-r--r--docs/ref/utils.txt4
-rw-r--r--docs/releases/1.2.4.txt2
-rw-r--r--docs/releases/1.3.txt2
-rw-r--r--docs/releases/1.6.txt71
-rw-r--r--docs/topics/auth/customizing.txt3
-rw-r--r--docs/topics/auth/default.txt5
-rw-r--r--docs/topics/auth/passwords.txt6
-rw-r--r--docs/topics/db/transactions.txt40
-rw-r--r--docs/topics/i18n/timezones.txt2
-rw-r--r--docs/topics/i18n/translation.txt4
-rw-r--r--docs/topics/serialization.txt2
-rw-r--r--docs/topics/testing/advanced.txt77
-rw-r--r--docs/topics/testing/doctests.txt81
-rw-r--r--docs/topics/testing/index.txt77
-rw-r--r--docs/topics/testing/overview.txt142
31 files changed, 592 insertions, 444 deletions
diff --git a/docs/faq/contributing.txt b/docs/faq/contributing.txt
index 6f2dfd906f..20950e88c5 100644
--- a/docs/faq/contributing.txt
+++ b/docs/faq/contributing.txt
@@ -27,7 +27,7 @@ to make it dead easy, even for someone who may not be intimately familiar with
that area of the code, to understand the problem and verify the fix:
* Are there clear instructions on how to reproduce the bug? If this
- touches a dependency (such as PIL), a contrib module, or a specific
+ touches a dependency (such as Pillow/PIL), a contrib module, or a specific
database, are those instructions clear enough even for someone not
familiar with it?
diff --git a/docs/index.txt b/docs/index.txt
index 6473aa3168..7f9d1bd032 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -185,8 +185,7 @@ testing of Django applications:
* **Testing:**
:doc:`Introduction <topics/testing/index>` |
:doc:`Writing and running tests <topics/testing/overview>` |
- :doc:`Advanced topics <topics/testing/advanced>` |
- :doc:`Doctests <topics/testing/doctests>`
+ :doc:`Advanced topics <topics/testing/advanced>`
* **Deployment:**
:doc:`Overview <howto/deployment/index>` |
diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt
index f891bc4eb7..6b9c7df14a 100644
--- a/docs/internals/committers.txt
+++ b/docs/internals/committers.txt
@@ -30,13 +30,10 @@ Journal-World`_ of Lawrence, Kansas, USA.
Simon lives in Brighton, England.
`Jacob Kaplan-Moss`_
- Jacob is a partner at `Revolution Systems`_ which provides support services
- around Django and related open source technologies. A good deal of Jacob's
- work time is devoted to working on Django. Jacob previously worked at World
- Online, where Django was invented, where he was the lead developer of
- Ellington, a commercial Web publishing platform for media companies.
-
- Jacob lives in Lawrence, Kansas, USA.
+ Jacob is Director of Platform Security at Heroku_. He worked at World
+ Online for four years, where he helped open source Django and found
+ the Django Software Foundation. Jacob lives on a hobby farm outside of
+ Lawrence where he spends his weekends playing with dirt and power tools.
`Wilson Miner`_
Wilson's design-fu is what makes Django look so nice. He designed the
@@ -55,6 +52,7 @@ Journal-World`_ of Lawrence, Kansas, USA.
.. _jacob kaplan-moss: http://jacobian.org/
.. _revolution systems: http://revsys.com/
.. _wilson miner: http://wilsonminer.com/
+.. _heroku: http://heroku.com/
Current developers
==================
@@ -200,7 +198,7 @@ Karen Tracey
He has worked on Django's auth, admin and staticfiles apps as well as
the form, core, internationalization and test systems. He currently works
- as the lead engineer at Gidsy_.
+ at Mozilla_.
Jannis lives in Berlin, Germany.
@@ -208,7 +206,7 @@ Karen Tracey
.. _Bauhaus-University Weimar: http://www.uni-weimar.de/
.. _virtualenv: http://www.virtualenv.org/
.. _pip: http://www.pip-installer.org/
-.. _Gidsy: http://gidsy.com/
+.. _Mozilla: http://www.mozilla.org/
`James Tauber`_
James is the lead developer of Pinax_ and the CEO and founder of
@@ -455,9 +453,6 @@ Jeremy Dunck
.. _`Daniel Lindsley`: http://toastdriven.com/
.. _`Amazon Web Services`: https://aws.amazon.com/
-Specialists
------------
-
`James Bennett`_
James is Django's release manager, and also contributes to the
documentation and provide the occasional bugfix.
@@ -508,6 +503,30 @@ Tim Graham
Tim works as a software engineer and lives in Philadelphia, PA, USA.
+Marc Tamlyn
+ Marc started life on the web using Django 1.2 back in 2010, and has never
+ looked back. He was involved with rewriting the class based view
+ documentation at DjangoCon EU 2012, and also helped to develop `CCBV`_, an
+ additional class based view reference tool.
+
+ Marc currently works at `Incuna Ltd`_, a digital healthcare agency in
+ Oxford, UK.
+
+.. _CCBV: http://ccbv.co.uk/
+.. _Incuna Ltd: http://incuna.com/
+
+Donald Stufft
+ Donald found Python and Django in 2007 while trying to find a language,
+ and web framework that he really enjoyed using after many years of PHP. He
+ fell in love with the beauty of Python and the way Django made tasks simple
+ and easy. His contributions to Django focus primarily on ensuring that it
+ is and remains a secure web framework.
+
+ Donald currently works at `Nebula Inc`_ as a Software Engineer for their
+ security team and lives in the Greater Philadelphia Area.
+
+.. _Nebula Inc: https://www.nebula.com/
+
Developers Emeritus
===================
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 1533e25dc8..774de2a2fd 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -73,7 +73,7 @@ these changes.
``django.utils.formats.get_format()`` to get the appropriate
formats.
-* The ability to use a function-based test runners will be removed,
+* The ability to use a function-based test runner will be removed,
along with the ``django.test.simple.run_tests()`` test runner.
* The ``views.feed()`` view and ``feeds.Feed`` class in
@@ -365,6 +365,12 @@ these changes.
* ``django.conf.urls.shortcut`` and ``django.views.defaults.shortcut`` will be
removed.
+* Support for the Python Imaging Library (PIL) module will be removed, as it
+ no longer appears to be actively maintained & does not work on Python 3.
+ You are advised to install `Pillow`_, which should be used instead.
+
+.. _`Pillow`: https://pypi.python.org/pypi/Pillow
+
* The following private APIs will be removed:
- ``django.db.close_connection()``
@@ -375,6 +381,15 @@ these changes.
* ``django.forms.widgets.RadioInput`` will be removed in favor of
``django.forms.widgets.RadioChoiceInput``.
+* The module ``django.test.simple`` and the class
+ ``django.test.simple.DjangoTestSuiteRunner`` will be removed. Instead use
+ ``django.test.runner.DiscoverRunner``.
+
+* The module ``django.test._doctest`` and the classes
+ ``django.test.testcases.DocTestRunner`` and
+ ``django.test.testcases.OutputChecker`` will be removed. Instead use the
+ doctest module from the Python standard library.
+
2.0
---
diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt
index 87d8e584ad..9f54243a3e 100644
--- a/docs/intro/tutorial04.txt
+++ b/docs/intro/tutorial04.txt
@@ -185,7 +185,7 @@ conversion. We will:
2. Delete some of the old, unneeded views.
-3. Fix up URL handling for the new views.
+3. Introduce new views based on Django's generic views.
Read on for details.
@@ -205,32 +205,51 @@ Amend URLconf
First, open the ``polls/urls.py`` URLconf and change it like so::
from django.conf.urls import patterns, url
- from django.views.generic import DetailView, ListView
- from polls.models import Poll
+
+ from polls import views
urlpatterns = patterns('',
- url(r'^$',
- ListView.as_view(
- queryset=Poll.objects.order_by('-pub_date')[:5],
- context_object_name='latest_poll_list',
- template_name='polls/index.html'),
- name='index'),
- url(r'^(?P<pk>\d+)/$',
- DetailView.as_view(
- model=Poll,
- template_name='polls/detail.html'),
- name='detail'),
- url(r'^(?P<pk>\d+)/results/$',
- DetailView.as_view(
- model=Poll,
- template_name='polls/results.html'),
- name='results'),
- url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote', name='vote'),
+ url(r'^$', views.IndexView.as_view(), name='index'),
+ url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
+ url(r'^(?P<pk>\d+)/results/$', views.ResultsView.as_view(), name='results'),
+ url(r'^(?P<poll_id>\d+)/vote/$', views.vote, name='vote'),
)
Amend views
-----------
+Next, we're going to remove our old ``index``, ``detail``, and ``results``
+views and use Django's generic views instead. To do so, open the
+``polls/views.py`` file and change it like so::
+
+ from django.shortcuts import get_object_or_404, render
+ from django.http import HttpResponseRedirect
+ from django.core.urlresolvers import reverse
+ from django.views import generic
+
+ from polls.models import Choice, Poll
+
+ class IndexView(generic.ListView):
+ template_name = 'polls/index.html'
+ context_object_name = 'latest_poll_list'
+
+ def get_queryset(self):
+ """Return the last five published polls."""
+ return Poll.objects.order_by('-pub_date')[:5]
+
+
+ class DetailView(generic.DetailView):
+ model = Poll
+ template_name = 'polls/detail.html'
+
+
+ class ResultsView(generic.DetailView):
+ model = Poll
+ template_name = 'polls/results.html'
+
+ def vote(request, poll_id):
+ ....
+
We're using two generic views here:
:class:`~django.views.generic.list.ListView` and
:class:`~django.views.generic.detail.DetailView`. Respectively, those
@@ -238,7 +257,7 @@ two views abstract the concepts of "display a list of objects" and
"display a detail page for a particular type of object."
* Each generic view needs to know what model it will be acting
- upon. This is provided using the ``model`` parameter.
+ upon. This is provided using the ``model`` attribute.
* The :class:`~django.views.generic.detail.DetailView` generic view
expects the primary key value captured from the URL to be called
@@ -248,7 +267,7 @@ two views abstract the concepts of "display a list of objects" and
By default, the :class:`~django.views.generic.detail.DetailView` generic
view uses a template called ``<app name>/<model name>_detail.html``.
In our case, it'll use the template ``"polls/poll_detail.html"``. The
-``template_name`` argument is used to tell Django to use a specific
+``template_name`` attribute is used to tell Django to use a specific
template name instead of the autogenerated default template name. We
also specify the ``template_name`` for the ``results`` list view --
this ensures that the results view and the detail view have a
@@ -268,16 +287,11 @@ automatically -- since we're using a Django model (``Poll``), Django
is able to determine an appropriate name for the context variable.
However, for ListView, the automatically generated context variable is
``poll_list``. To override this we provide the ``context_object_name``
-option, specifying that we want to use ``latest_poll_list`` instead.
+attribute, specifying that we want to use ``latest_poll_list`` instead.
As an alternative approach, you could change your templates to match
the new default context variables -- but it's a lot easier to just
tell Django to use the variable you want.
-You can now delete the ``index()``, ``detail()`` and ``results()`` views from
-``polls/views.py``. We don't need them anymore -- they have been replaced by
-generic views. You can also delete the import for ``HttpResponse``, which is no
-longer required.
-
Run the server, and use your new polling app based on generic views.
For full details on generic views, see the :doc:`generic views documentation
diff --git a/docs/intro/tutorial05.txt b/docs/intro/tutorial05.txt
index 97d1d96ad7..a276763d67 100644
--- a/docs/intro/tutorial05.txt
+++ b/docs/intro/tutorial05.txt
@@ -156,8 +156,9 @@ Create a test to expose the bug
What we've just done in the shell to test for the problem is exactly what we
can do in an automated test, so let's turn that into an automated test.
-The best place for an application's tests is in the application's ``tests.py``
-file - the testing system will look there for tests automatically.
+A conventional place for an application's tests is in the application's
+``tests.py`` file; the testing system will automatically find tests in any file
+whose name begins with ``test``.
Put the following in the ``tests.py`` file in the ``polls`` application::
@@ -377,45 +378,40 @@ Improving our view
The list of polls shows polls that aren't published yet (i.e. those that have a
``pub_date`` in the future). Let's fix that.
-In :doc:`Tutorial 4 </intro/tutorial04>` we deleted the view functions from
-``views.py`` in favor of a :class:`~django.views.generic.list.ListView` in
-``urls.py``::
+In :doc:`Tutorial 4 </intro/tutorial04>` we introduced a class-based view,
+based on :class:`~django.views.generic.list.ListView`::
- url(r'^$',
- ListView.as_view(
- queryset=Poll.objects.order_by('-pub_date')[:5],
- context_object_name='latest_poll_list',
- template_name='polls/index.html'),
- name='index'),
+ class IndexView(generic.ListView):
+ template_name = 'polls/index.html'
+ context_object_name = 'latest_poll_list'
+
+ def get_queryset(self):
+ """Return the last five published polls."""
+ return Poll.objects.order_by('-pub_date')[:5]
``response.context_data['latest_poll_list']`` extracts the data this view
places into the context.
-We need to amend the line that gives us the ``queryset``::
-
- queryset=Poll.objects.order_by('-pub_date')[:5],
-
-Let's change the queryset so that it also checks the date by comparing it with
-``timezone.now()``. First we need to add an import::
+We need to amend the ``get_queryset`` method and change it so that it also
+checks the date by comparing it with ``timezone.now()``. First we need to add
+an import::
from django.utils import timezone
-and then we must amend the existing ``url`` function to::
+and then we must amend the ``get_queryset`` method like so::
- url(r'^$',
- ListView.as_view(
- queryset=Poll.objects.filter(pub_date__lte=timezone.now) \
- .order_by('-pub_date')[:5],
- context_object_name='latest_poll_list',
- template_name='polls/index.html'),
- name='index'),
+ def get_queryset(self):
+ """
+ Return the last five published polls (not including those set to be
+ published in the future).
+ """
+ return Poll.objects.filter(
+ pub_date__lte=timezone.now()
+ ).order_by('-pub_date')[:5]
-``Poll.objects.filter(pub_date__lte=timezone.now)`` returns a queryset
+``Poll.objects.filter(pub_date__lte=timezone.now())`` returns a queryset
containing Polls whose ``pub_date`` is less than or equal to - that is, earlier
-than or equal to - ``timezone.now``. Notice that we use a callable queryset
-argument, ``timezone.now``, which will be evaluated at request time. If we had
-included the parentheses, ``timezone.now()`` would be evaluated just once when
-the web server is started.
+than or equal to - ``timezone.now``.
Testing our new view
--------------------
@@ -526,20 +522,18 @@ Testing the ``DetailView``
What we have works well; however, even though future polls don't appear in the
*index*, users can still reach them if they know or guess the right URL. So we
-need similar constraints in the ``DetailViews``, by adding::
-
- queryset=Poll.objects.filter(pub_date__lte=timezone.now)
+need to add a similar constraint to ``DetailView``::
-to them - for example::
- url(r'^(?P<pk>\d+)/$',
- DetailView.as_view(
- queryset=Poll.objects.filter(pub_date__lte=timezone.now),
- model=Poll,
- template_name='polls/detail.html'),
- name='detail'),
+ class DetailView(generic.DetailView):
+ ...
+ def get_queryset(self):
+ """
+ Excludes any polls that aren't published yet.
+ """
+ return Poll.objects.filter(pub_date__lte=timezone.now())
-and of course, we will add some tests, to check that a ``Poll`` whose
+And of course, we will add some tests, to check that a ``Poll`` whose
``pub_date`` is in the past can be displayed, and that one with a ``pub_date``
in the future is not::
@@ -565,9 +559,9 @@ in the future is not::
Ideas for more tests
--------------------
-We ought to add similar ``queryset`` arguments to the other ``DetailView``
-URLs, and create a new test class for each view. They'll be very similar to
-what we have just created; in fact there will be a lot of repetition.
+We ought to add a similar ``get_queryset`` method to ``ResultsView`` and
+create a new test class for that view. It'll be very similar to what we have
+just created; in fact there will be a lot of repetition.
We could also improve our application in other ways, adding tests along the
way. For example, it's silly that ``Polls`` can be published on the site that
diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt
index 3ba7c38c43..ee0bf0f225 100644
--- a/docs/ref/class-based-views/base.txt
+++ b/docs/ref/class-based-views/base.txt
@@ -9,7 +9,7 @@ required for projects, in which case there are Mixins and Generic class-based
views.
Many of Django's built-in class-based views inherit from other class-based
-views or various mixins. Because this inheritence chain is very important, the
+views or various mixins. Because this inheritance chain is very important, the
ancestor classes are documented under the section title of **Ancestors (MRO)**.
MRO is an acronym for Method Resolution Order.
diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt
index b3e26eca48..394d078e5b 100644
--- a/docs/ref/contrib/admin/admindocs.txt
+++ b/docs/ref/contrib/admin/admindocs.txt
@@ -57,9 +57,10 @@ Model reference
===============
The **models** section of the ``admindocs`` page describes each model in the
-system along with all the fields and methods available on it. Relationships to
-other models appear as hyperlinks. Descriptions are pulled from ``help_text``
-attributes on fields or from docstrings on model methods.
+system along with all the fields and methods (without any arguments) available
+on it. While model properties don't have any arguments, they are not listed.
+Relationships to other models appear as hyperlinks. Descriptions are pulled
+from ``help_text`` attributes on fields or from docstrings on model methods.
A model with useful documentation might look like this::
diff --git a/docs/ref/contrib/gis/forms-api.txt b/docs/ref/contrib/gis/forms-api.txt
new file mode 100644
index 0000000000..d0c671958f
--- /dev/null
+++ b/docs/ref/contrib/gis/forms-api.txt
@@ -0,0 +1,165 @@
+.. _ref-gis-forms-api:
+
+===================
+GeoDjango Forms API
+===================
+
+.. module:: django.contrib.gis.forms
+ :synopsis: GeoDjango forms API.
+
+.. versionadded:: 1.6
+
+GeoDjango provides some specialized form fields and widgets in order to visually
+display and edit geolocalized data on a map. By default, they use
+`OpenLayers`_-powered maps, with a base WMS layer provided by `Metacarta`_.
+
+.. _OpenLayers: http://openlayers.org/
+.. _Metacarta: http://metacarta.com/
+
+Field arguments
+===============
+In addition to the regular :ref:`form field arguments <core-field-arguments>`,
+GeoDjango form fields take the following optional arguments.
+
+``srid``
+~~~~~~~~
+
+.. attribute:: Field.srid
+
+ This is the SRID code that the field value should be transformed to. For
+ example, if the map widget SRID is different from the SRID more generally
+ used by your application or database, the field will automatically convert
+ input values into that SRID.
+
+``geom_type``
+~~~~~~~~~~~~~
+
+.. attribute:: Field.geom_type
+
+ You generally shouldn't have to set or change that attribute which should
+ be setup depending on the field class. It matches the OpenGIS standard
+ geometry name.
+
+Form field classes
+==================
+
+``GeometryField``
+~~~~~~~~~~~~~~~~~
+
+.. class:: GeometryField
+
+``PointField``
+~~~~~~~~~~~~~~
+
+.. class:: PointField
+
+``LineStringField``
+~~~~~~~~~~~~~~~~~~~
+
+.. class:: LineStringField
+
+``PolygonField``
+~~~~~~~~~~~~~~~~
+
+.. class:: PolygonField
+
+``MultiPointField``
+~~~~~~~~~~~~~~~~~~~
+
+.. class:: MultiPointField
+
+``MultiLineStringField``
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: MultiLineStringField
+
+``MultiPolygonField``
+~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: MultiPolygonField
+
+``GeometryCollectionField``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: GeometryCollectionField
+
+Form widgets
+============
+
+.. module:: django.contrib.gis.widgets
+ :synopsis: GeoDjango widgets API.
+
+GeoDjango form widgets allow you to display and edit geographic data on a
+visual map.
+Note that none of the currently available widgets supports 3D geometries, hence
+geometry fields will fallback using a simple ``Textarea`` widget for such data.
+
+Widget attributes
+~~~~~~~~~~~~~~~~~
+
+GeoDjango widgets are template-based, so their attributes are mostly different
+from other Django widget attributes.
+
+
+.. attribute:: BaseGeometryWidget.geom_type
+
+ The OpenGIS geometry type, generally set by the form field.
+
+.. attribute:: BaseGeometryWidget.map_height
+.. attribute:: BaseGeometryWidget.map_width
+
+ Height and width of the widget map (default is 400x600).
+
+.. attribute:: BaseGeometryWidget.map_srid
+
+ SRID code used by the map (default is 4326).
+
+.. attribute:: BaseGeometryWidget.display_wkt
+
+ Boolean value specifying if a textarea input showing the WKT representation
+ of the current geometry is visible, mainly for debugging purposes (default
+ is ``False``).
+
+.. attribute:: BaseGeometryWidget.supports_3d
+
+ Indicates if the widget supports edition of 3D data (default is ``False``).
+
+.. attribute:: BaseGeometryWidget.template_name
+
+ The template used to render the map widget.
+
+You can pass widget attributes in the same manner that for any other Django
+widget. For example::
+
+ from django.contrib.gis import forms
+
+ class MyGeoForm(forms.Form):
+ point = forms.PointField(widget=
+ forms.OSMWidget(attrs={'map_width': 800, 'map_height': 500}))
+
+Widget classes
+~~~~~~~~~~~~~~
+
+``BaseGeometryWidget``
+
+.. class:: BaseGeometryWidget
+
+ This is an abstract base widget containing the logic needed by subclasses.
+ You cannot directly use this widget for a geometry field.
+ Note that the rendering of GeoDjango widgets is based on a template,
+ identified by the :attr:`template_name` class attribute.
+
+``OpenLayersWidget``
+
+.. class:: OpenLayersWidget
+
+ This is the default widget used by all GeoDjango form fields.
+ ``template_name`` is ``gis/openlayers.html``.
+
+``OSMWidget``
+
+.. class:: OSMWidget
+
+ This widget uses an OpenStreetMap base layer (Mapnik) to display geographic
+ objects on.
+ ``template_name`` is ``gis/openlayers-osm.html``.
diff --git a/docs/ref/contrib/gis/index.txt b/docs/ref/contrib/gis/index.txt
index 6a1402bfab..c533aa459d 100644
--- a/docs/ref/contrib/gis/index.txt
+++ b/docs/ref/contrib/gis/index.txt
@@ -18,6 +18,7 @@ of spatially enabled data.
install/index
model-api
db-api
+ forms-api
geoquerysets
measure
geos
diff --git a/docs/ref/contrib/gis/testing.txt b/docs/ref/contrib/gis/testing.txt
index 2a6dcef46f..fca6675345 100644
--- a/docs/ref/contrib/gis/testing.txt
+++ b/docs/ref/contrib/gis/testing.txt
@@ -134,57 +134,14 @@ your settings::
GeoDjango tests
===============
-GeoDjango's test suite may be run in one of two ways, either by itself or
-with the rest of :ref:`Django's unit tests <running-unit-tests>`.
+To have the GeoDjango tests executed when :ref:`running the Django test suite
+<running-unit-tests>` with ``runtests.py`` all of the databases in the settings
+file must be using one of the :ref:`spatial database backends
+<spatial-backends>`.
-Run only GeoDjango tests
-------------------------
-
-.. class:: django.contrib.gis.tests.GeoDjangoTestSuiteRunner
-
-To run *only* the tests for GeoDjango, the :setting:`TEST_RUNNER`
-setting must be changed to use the
-:class:`~django.contrib.gis.tests.GeoDjangoTestSuiteRunner`::
-
- TEST_RUNNER = 'django.contrib.gis.tests.GeoDjangoTestSuiteRunner'
Example
-^^^^^^^
-
-First, you'll need a bare-bones settings file, like below, that is
-customized with your spatial database name and user::
-
- TEST_RUNNER = 'django.contrib.gis.tests.GeoDjangoTestSuiteRunner'
-
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.contrib.gis.db.backends.postgis',
- 'NAME': 'a_spatial_database',
- 'USER': 'db_user'
- }
- }
-
-Assuming the above is in a file called ``postgis.py`` that is in the
-the same directory as ``manage.py`` of your Django project, then
-you may run the tests with the following command::
-
- $ python manage.py test --settings=postgis
-
-Run with ``runtests.py``
-------------------------
-
-To have the GeoDjango tests executed when
-:ref:`running the Django test suite <running-unit-tests>` with ``runtests.py``
-all of the databases in the settings file must be using one of the
-:ref:`spatial database backends <spatial-backends>`.
-
-.. warning::
-
- Do not change the :setting:`TEST_RUNNER` setting
- when running the GeoDjango tests with ``runtests.py``.
-
-Example
-^^^^^^^
+-------
The following is an example bare-bones settings file with spatial backends
that can be used to run the entire Django test suite, including those
@@ -208,3 +165,7 @@ directory as ``runtests.py``, then all Django and GeoDjango tests would
be performed when executing the command::
$ ./runtests.py --settings=postgis
+
+To run only the GeoDjango test suite, specify ``django.contrib.gis``::
+
+ $ ./runtests.py --settings=postgis django.contrib.gis
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index ec49705add..2f2880679c 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -373,7 +373,46 @@ application, ``<dirname>/foo/bar/mydata.json`` for each directory in
:setting:`FIXTURE_DIRS`, and the literal path ``foo/bar/mydata.json``.
When fixture files are processed, the data is saved to the database as is.
-Model defined ``save`` methods and ``pre_save`` signals are not called.
+Model defined :meth:`~django.db.models.Model.save` methods are not called, and
+any :data:`~django.db.models.signals.pre_save` or
+:data:`~django.db.models.signals.post_save` signals will be called with
+``raw=True`` since the instance only contains attributes that are local to the
+model. You may, for example, want to disable handlers that access
+related fields that aren't present during fixture loading and would otherwise
+raise an exception::
+
+ from django.db.models.signals import post_save
+ from .models import MyModel
+
+ def my_handler(**kwargs):
+ # disable the handler during fixture loading
+ if kwargs['raw']:
+ return
+ ...
+
+ post_save.connect(my_handler, sender=MyModel)
+
+You could also write a simple decorator to encapsulate this logic::
+
+ from functools import wraps
+
+ def disable_for_loaddata(signal_handler):
+ """
+ Decorator that turns off signal handlers when loading fixture data.
+ """
+ @wraps(signal_handler)
+ def wrapper(*args, **kwargs):
+ if kwargs['raw']:
+ return
+ signal_handler(*args, **kwargs)
+ return wrapper
+
+ @disable_for_loaddata
+ def my_handler(**kwargs):
+ ...
+
+Just be aware that this logic will disable the signals whenever fixtures are
+deserialized, not just during ``loaddata``.
Note that the order in which fixture files are processed is undefined. However,
all fixture data is installed as a single transaction, so data in
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 29f889445d..8e1a4b34d1 100644
--- a/docs/ref/forms/fields.txt
+++ b/docs/ref/forms/fields.txt
@@ -30,6 +30,8 @@ exception or returns the clean value::
...
ValidationError: [u'Enter a valid email address.']
+.. _core-field-arguments:
+
Core field arguments
--------------------
@@ -608,19 +610,21 @@ For each field, we describe the default widget used if you don't specify
* Normalizes to: An ``UploadedFile`` object that wraps the file content
and file name into a single object.
* Validates that file data has been bound to the form, and that the
- file is of an image format understood by PIL.
+ file is of an image format understood by Pillow/PIL.
* Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
``invalid_image``
- Using an ``ImageField`` requires that the `Python Imaging Library`_ (PIL)
- is installed and supports the image formats you use. If you encounter a
- ``corrupt image`` error when you upload an image, it usually means PIL
+ Using an ``ImageField`` requires that either `Pillow`_ (recommended) or the
+ `Python Imaging Library`_ (PIL) are installed and supports the image
+ formats you use. If you encounter a ``corrupt image`` error when you
+ upload an image, it usually means either Pillow or PIL
doesn't understand its format. To fix this, install the appropriate
- library and reinstall PIL.
+ library and reinstall Pillow or PIL.
When you use an ``ImageField`` on a form, you must also remember to
:ref:`bind the file data to the form <binding-uploaded-files>`.
+.. _Pillow: http://python-imaging.github.io/Pillow/
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
``IntegerField``
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index d322904ec9..99ba78cb09 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -287,6 +287,9 @@ For example, if you have a field ``title`` that has
``unique_for_date="pub_date"``, then Django wouldn't allow the entry of two
records with the same ``title`` and ``pub_date``.
+Note that if you set this to point to a :class:`DateTimeField`, only the date
+portion of the field will be considered.
+
This is enforced by model validation but not at the database level.
``unique_for_month``
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index d27214a66c..ffada19082 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -328,7 +328,7 @@ Use the ``reverse()`` method to reverse the order in which a queryset's
elements are returned. Calling ``reverse()`` a second time restores the
ordering back to the normal direction.
-To retrieve the ''last'' five items in a queryset, you could do this::
+To retrieve the "last" five items in a queryset, you could do this::
my_queryset.reverse()[:5]
@@ -1486,7 +1486,7 @@ internally so that repeated evaluations do not result in additional queries. In
contrast, ``iterator()`` will read results directly, without doing any caching
at the ``QuerySet`` level (internally, the default iterator calls ``iterator()``
and caches the return value). For a ``QuerySet`` which returns a large number of
-objects that you only need to access once, this can results in better
+objects that you only need to access once, this can result in better
performance and a significant reduction in memory.
Note that using ``iterator()`` on a ``QuerySet`` which has already been
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 04b42aeeb2..eb470cdd14 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -1725,11 +1725,16 @@ misspelled) variables. See :ref:`invalid-template-variables`..
TEST_RUNNER
-----------
-Default: ``'django.test.simple.DjangoTestSuiteRunner'``
+Default: ``'django.test.runner.DiscoverRunner'``
The name of the class to use for starting the test suite. See
:ref:`other-testing-frameworks`.
+.. versionchanged:: 1.6
+
+ Previously the default ``TEST_RUNNER`` was
+ ``django.test.simple.DjangoTestSuiteRunner``.
+
.. setting:: THOUSAND_SEPARATOR
THOUSAND_SEPARATOR
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index a7d5b6690e..14ae9aa9b8 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -659,11 +659,11 @@ Functions for working with Python modules.
wrong. For example::
from django.utils.module_loading import import_by_path
- import_by_path = import_by_path('django.utils.module_loading.import_by_path')
+ ImproperlyConfigured = import_by_path('django.core.exceptions.ImproperlyConfigured')
is equivalent to::
- from django.utils.module_loading import import_by_path
+ from django.core.exceptions import ImproperlyConfigured
``django.utils.safestring``
===========================
diff --git a/docs/releases/1.2.4.txt b/docs/releases/1.2.4.txt
index b74ea9aef2..ae15ea6f7c 100644
--- a/docs/releases/1.2.4.txt
+++ b/docs/releases/1.2.4.txt
@@ -78,7 +78,7 @@ GeoDjango
The function-based :setting:`TEST_RUNNER` previously used to execute
the GeoDjango test suite, ``django.contrib.gis.tests.run_gis_tests``,
was finally deprecated in favor of a class-based test runner,
-:class:`django.contrib.gis.tests.GeoDjangoTestSuiteRunner`, added in this
+``django.contrib.gis.tests.GeoDjangoTestSuiteRunner``, added in this
release.
In addition, the GeoDjango test suite is now included when
diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt
index 9a41f903f8..89cece941b 100644
--- a/docs/releases/1.3.txt
+++ b/docs/releases/1.3.txt
@@ -799,7 +799,7 @@ GeoDjango
* The function-based :setting:`TEST_RUNNER` previously used to execute
the GeoDjango test suite, ``django.contrib.gis.tests.run_gis_tests``, was
deprecated for the class-based runner,
- :class:`django.contrib.gis.tests.GeoDjangoTestSuiteRunner`.
+ ``django.contrib.gis.tests.GeoDjangoTestSuiteRunner``.
* Previously, calling
:meth:`~django.contrib.gis.geos.GEOSGeometry.transform` would
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index 9cce36aac3..98889254cd 100644
--- a/docs/releases/1.6.txt
+++ b/docs/releases/1.6.txt
@@ -69,6 +69,29 @@ This avoids the overhead of re-establishing a connection at the beginning of
each request. For backwards compatibility, this feature is disabled by
default. See :ref:`persistent-database-connections` for details.
+Discovery of tests in any test module
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django 1.6 ships with a new test runner that allows more flexibility in the
+location of tests. The previous runner
+(``django.test.simple.DjangoTestSuiteRunner``) found tests only in the
+``models.py`` and ``tests.py`` modules of a Python package in
+:setting:`INSTALLED_APPS`.
+
+The new runner (``django.test.runner.DjangoTestDiscoverRunner``) uses the test
+discovery features built into unittest2 (the version of unittest in the Python
+2.7+ standard library, and bundled with Django). With test discovery, tests can
+be located in any module whose name matches the pattern ``test*.py``.
+
+In addition, the test labels provided to ``./manage.py test`` to nominate
+specific tests to run must now be full Python dotted paths (or directory
+paths), rather than ``applabel.TestCase.test_method_name`` pseudo-paths. This
+allows running tests located anywhere in your codebase, rather than only in
+:setting:`INSTALLED_APPS`. For more details, see :doc:`/topics/testing/index`.
+
+This change is backwards-incompatible; see the :ref:`backwards-incompatibility
+notes<new-test-runner>`.
+
Time zone aware aggregation
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -91,6 +114,13 @@ Django 1.6 adds support for savepoints in SQLite, with some :ref:`limitations
A new :class:`django.db.models.BinaryField` model field allows to store raw
binary data in the database.
+GeoDjango form widgets
+~~~~~~~~~~~~~~~~~~~~~~
+
+GeoDjango now provides :ref:`form fields and widgets <ref-gis-forms-api>` for
+its geo-specialized fields. They are OpenLayers-based by default, but they can
+be customized to use any other JS framework.
+
Minor features
~~~~~~~~~~~~~~
@@ -197,6 +227,13 @@ Minor features
* Added ``BCryptSHA256PasswordHasher`` to resolve the password truncation issue
with bcrypt.
+* `Pillow`_ is now the preferred image manipulation library to use with Django.
+ `PIL`_ is pending deprecation (support to be removed in Django 1.8).
+ To upgrade, you should **first** uninstall PIL, **then** install Pillow.
+
+.. _`Pillow`: https://pypi.python.org/pypi/Pillow
+.. _`PIL`: https://pypi.python.org/pypi/PIL
+
Backwards incompatible changes in 1.6
=====================================
@@ -238,6 +275,40 @@ In previous versions, database-level autocommit was only an option for
PostgreSQL, and it was disabled by default. This option is now :ref:`ignored
<postgresql-autocommit-mode>` and can be removed.
+.. _new-test-runner:
+
+New test runner
+~~~~~~~~~~~~~~~
+
+In order to maintain greater consistency with Python's unittest module, the new
+test runner (``django.test.runner.DiscoverRunner``) does not automatically
+support some types of tests that were supported by the previous runner:
+
+* Tests in ``models.py`` and ``tests/__init__.py`` files will no longer be
+ found and run. Move them to a file whose name begins with ``test``.
+
+* Doctests will no longer be automatically discovered. To integrate doctests in
+ your test suite, follow the `recommendations in the Python documentation`_.
+
+Django bundles a modified version of the :mod:`doctest` module from the Python
+standard library (in ``django.test._doctest``) in order to allow passing in a
+custom ``DocTestRunner`` when instantiating a ``DocTestSuite``, and includes
+some additional doctest utilities (``django.test.testcases.DocTestRunner``
+turns on the ``ELLIPSIS`` option by default, and
+``django.test.testcases.OutputChecker`` provides better matching of XML, JSON,
+and numeric data types).
+
+These utilities are deprecated and will be removed in Django 1.8; doctest
+suites should be updated to work with the standard library's doctest module (or
+converted to unittest-compatible tests).
+
+If you wish to delay updates to your test suite, you can set your
+:setting:`TEST_RUNNER` setting to ``django.test.simple.DjangoTestSuiteRunner``
+to fully restore the old test behavior. ``DjangoTestSuiteRunner`` is
+deprecated but will not be removed from Django until version 1.8.
+
+.. _recommendations in the Python documentation: http://docs.python.org/2/library/doctest.html#unittest-api
+
Addition of ``QuerySet.datetimes()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt
index b53bbe8211..56f3e60350 100644
--- a/docs/topics/auth/customizing.txt
+++ b/docs/topics/auth/customizing.txt
@@ -95,7 +95,8 @@ An authentication backend is a class that implements two required methods:
optional permission related :ref:`authorization methods <authorization_methods>`.
The ``get_user`` method takes a ``user_id`` -- which could be a username,
-database ID or whatever -- and returns a ``User`` object.
+database ID or whatever, but has to be the primary key of your ``User`` object
+-- and returns a ``User`` object.
The ``authenticate`` method takes credentials as keyword arguments. Most of
the time, it'll just look like this::
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index e666cded75..8849520b11 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -939,10 +939,15 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
A form used in the admin interface to change a user's password.
+ Takes the ``user`` as the first positional argument.
+
.. class:: AuthenticationForm
A form for logging a user in.
+ Takes ``request`` as its first positional argument, which is stored on the
+ form instance for use by sub-classes.
+
.. class:: PasswordChangeForm
A form for allowing a user to change their password.
diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt
index 2193e6a3c7..206e7d856c 100644
--- a/docs/topics/auth/passwords.txt
+++ b/docs/topics/auth/passwords.txt
@@ -76,8 +76,8 @@ use it Django supports bcrypt with minimal effort.
To use Bcrypt as your default storage algorithm, do the following:
-1. Install the `py-bcrypt`_ library (probably by running ``sudo pip install
- py-bcrypt``, or downloading the library and installing it with ``python
+1. Install the `bcrypt library`_ (probably by running ``sudo pip install
+ bcrypt``, or downloading the library and installing it with ``python
setup.py install``).
2. Modify :setting:`PASSWORD_HASHERS` to list ``BCryptSHA256PasswordHasher``
@@ -185,7 +185,7 @@ mentioned algorithms won't be able to upgrade.
.. _pbkdf2: http://en.wikipedia.org/wiki/PBKDF2
.. _nist: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
.. _bcrypt: http://en.wikipedia.org/wiki/Bcrypt
-.. _py-bcrypt: http://pypi.python.org/pypi/py-bcrypt/
+.. _`bcrypt library`: https://pypi.python.org/pypi/bcrypt/
Manually managing a user's password
diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
index 255584c68b..78786996cd 100644
--- a/docs/topics/db/transactions.txt
+++ b/docs/topics/db/transactions.txt
@@ -92,19 +92,15 @@ Django provides a single API to control database transactions.
.. function:: atomic(using=None, savepoint=True)
- This function creates an atomic block for writes to the database.
- (Atomicity is the defining property of database transactions.)
+ Atomicity is the defining property of database transactions. ``atomic``
+ allows us to create a block of code within which the atomicity on the
+ database is guaranteed. If the block of code is successfully completed, the
+ changes are committed to the database. If there is an exception, the
+ changes are rolled back.
- When the block completes successfully, the changes are committed to the
- database. When it raises an exception, the changes are rolled back.
-
- ``atomic`` can be nested. In this case, when an inner block completes
- successfully, its effects can still be rolled back if an exception is
- raised in the outer block at a later point.
-
- ``atomic`` takes a ``using`` argument which should be the name of a
- database. If this argument isn't provided, Django uses the ``"default"``
- database.
+ ``atomic`` blocks can be nested. In this case, when an inner block
+ completes successfully, its effects can still be rolled back if an
+ exception is raised in the outer block at a later point.
``atomic`` is usable both as a `decorator`_::
@@ -137,24 +133,32 @@ Django provides a single API to control database transactions.
@transaction.atomic
def viewfunc(request):
- do_stuff()
+ create_parent()
try:
with transaction.atomic():
- do_stuff_that_could_fail()
+ generate_relationships()
except IntegrityError:
handle_exception()
- do_more_stuff()
+ add_children()
- In this example, even if ``do_stuff_that_could_fail()`` causes a database
+ In this example, even if ``generate_relationships()`` causes a database
error by breaking an integrity constraint, you can execute queries in
- ``do_more_stuff()``, and the changes from ``do_stuff()`` are still there.
+ ``add_children()``, and the changes from ``create_parent()`` are still
+ there. Note that any operations attempted in ``generate_relationships()``
+ will already have been rolled back safely when ``handle_exception()`` is
+ called, so the exception handler can also operate on the database if
+ necessary.
In order to guarantee atomicity, ``atomic`` disables some APIs. Attempting
to commit, roll back, or change the autocommit state of the database
connection within an ``atomic`` block will raise an exception.
+ ``atomic`` takes a ``using`` argument which should be the name of a
+ database. If this argument isn't provided, Django uses the ``"default"``
+ database.
+
Under the hood, Django's transaction management code:
- opens a transaction when entering the outermost ``atomic`` block;
@@ -516,7 +520,7 @@ Transaction states
The three functions described above relied on a concept called "transaction
states". This mechanisme was deprecated in Django 1.6, but it's still
-available until Django 1.8..
+available until Django 1.8.
At any time, each database connection is in one of these two states:
diff --git a/docs/topics/i18n/timezones.txt b/docs/topics/i18n/timezones.txt
index 22a0edb073..e4a043b08f 100644
--- a/docs/topics/i18n/timezones.txt
+++ b/docs/topics/i18n/timezones.txt
@@ -189,6 +189,8 @@ Add the following middleware to :setting:`MIDDLEWARE_CLASSES`::
tz = request.session.get('django_timezone')
if tz:
timezone.activate(tz)
+ else:
+ timezone.deactivate()
Create a view that can set the current timezone::
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 2ce9d8d2bc..5b4ffea528 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -1437,7 +1437,9 @@ Here's example HTML template code:
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
- <option value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
+ <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
+ {{ language.name_local }} ({{ language.code }})
+ </option>
{% endfor %}
</select>
<input type="submit" value="Go" />
diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt
index cb34117997..e88e16029e 100644
--- a/docs/topics/serialization.txt
+++ b/docs/topics/serialization.txt
@@ -203,7 +203,7 @@ Foreign keys and other relational fields are treated a little bit differently::
<!-- ... -->
</object>
-In this example we specify that the auth.Permission object with the PK 24 has
+In this example we specify that the auth.Permission object with the PK 27 has
a foreign key to the contenttypes.ContentType instance with the PK 9.
ManyToMany-relations are exported for the model that binds them. For instance,
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index 5f2fa65bed..cefb770469 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -165,7 +165,7 @@ environment first. Django provides a convenience method to do this::
:func:`~django.test.utils.setup_test_environment` puts several Django features
into modes that allow for repeatable testing, but does not create the test
-databases; :func:`django.test.simple.DjangoTestSuiteRunner.setup_databases`
+databases; :func:`django.test.runner.DiscoverRunner.setup_databases`
takes care of that.
The call to :func:`~django.test.utils.setup_test_environment` is made
@@ -178,27 +178,27 @@ tests via Django's test runner.
Using different testing frameworks
==================================
-Clearly, :mod:`doctest` and :mod:`unittest` are not the only Python testing
-frameworks. While Django doesn't provide explicit support for alternative
-frameworks, it does provide a way to invoke tests constructed for an
-alternative framework as if they were normal Django tests.
+Clearly, :mod:`unittest` is not the only Python testing framework. While Django
+doesn't provide explicit support for alternative frameworks, it does provide a
+way to invoke tests constructed for an alternative framework as if they were
+normal Django tests.
When you run ``./manage.py test``, Django looks at the :setting:`TEST_RUNNER`
setting to determine what to do. By default, :setting:`TEST_RUNNER` points to
-``'django.test.simple.DjangoTestSuiteRunner'``. This class defines the default Django
+``'django.test.runner.DiscoverRunner'``. This class defines the default Django
testing behavior. This behavior involves:
#. Performing global pre-test setup.
-#. Looking for unit tests and doctests in the ``models.py`` and
- ``tests.py`` files in each installed application.
+#. Looking for tests in any file below the current directory whose name matches
+ the pattern ``test*.py``.
#. Creating the test databases.
#. Running ``syncdb`` to install models and initial data into the test
databases.
-#. Running the unit tests and doctests that are found.
+#. Running the tests that were found.
#. Destroying the test databases.
@@ -215,15 +215,22 @@ process to satisfy whatever testing requirements you may have.
Defining a test runner
----------------------
-.. currentmodule:: django.test.simple
+.. currentmodule:: django.test.runner
A test runner is a class defining a ``run_tests()`` method. Django ships
-with a ``DjangoTestSuiteRunner`` class that defines the default Django
+with a ``DiscoverRunner`` class that defines the default Django
testing behavior. This class defines the ``run_tests()`` entry point,
plus a selection of other methods that are used to by ``run_tests()`` to
set up, execute and tear down the test suite.
-.. class:: DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True, **kwargs)
+.. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=True, **kwargs)
+
+ ``DiscoverRunner`` will search for tests in any file matching ``pattern``.
+
+ ``top_level`` can be used to specify the directory containing your
+ top-level Python modules. Usually Django can figure this out automatically,
+ so it's not necessary to specify this option. If specified, it should
+ generally be the directory containing your ``manage.py`` file.
``verbosity`` determines the amount of notification and debug information
that will be printed to the console; ``0`` is no output, ``1`` is normal
@@ -238,11 +245,10 @@ set up, execute and tear down the test suite.
If ``failfast`` is ``True``, the test suite will stop running after the
first test failure is detected.
- Django will, from time to time, extend the capabilities of
- the test runner by adding new arguments. The ``**kwargs`` declaration
- allows for this expansion. If you subclass ``DjangoTestSuiteRunner`` or
- write your own test runner, ensure accept and handle the ``**kwargs``
- parameter.
+ Django may, from time to time, extend the capabilities of the test runner
+ by adding new arguments. The ``**kwargs`` declaration allows for this
+ expansion. If you subclass ``DiscoverRunner`` or write your own test
+ runner, ensure it accepts ``**kwargs``.
Your test runner may also define additional command-line options.
If you add an ``option_list`` attribute to a subclassed test runner,
@@ -252,7 +258,7 @@ set up, execute and tear down the test suite.
Attributes
~~~~~~~~~~
-.. attribute:: DjangoTestSuiteRunner.option_list
+.. attribute:: DiscoverRunner.option_list
This is the tuple of ``optparse`` options which will be fed into the
management command's ``OptionParser`` for parsing arguments. See the
@@ -261,20 +267,25 @@ Attributes
Methods
~~~~~~~
-.. method:: DjangoTestSuiteRunner.run_tests(test_labels, extra_tests=None, **kwargs)
+.. method:: DiscoverRunner.run_tests(test_labels, extra_tests=None, **kwargs)
Run the test suite.
``test_labels`` is a list of strings describing the tests to be run. A test
- label can take one of three forms:
+ label can take one of four forms:
- * ``app.TestCase.test_method`` -- Run a single test method in a test
+ * ``path.to.test_module.TestCase.test_method`` -- Run a single test method
+ in a test case.
+ * ``path.to.test_module.TestCase`` -- Run all the test methods in a test
case.
- * ``app.TestCase`` -- Run all the test methods in a test case.
- * ``app`` -- Search for and run all tests in the named application.
+ * ``path.to.module`` -- Search for and run all tests in the named Python
+ package or module.
+ * ``path/to/directory`` -- Search for and run all tests below the named
+ directory.
- If ``test_labels`` has a value of ``None``, the test runner should run
- search for tests in all the applications in :setting:`INSTALLED_APPS`.
+ If ``test_labels`` has a value of ``None``, the test runner will search for
+ tests in all files below the current directory whose names match its
+ ``pattern`` (see above).
``extra_tests`` is a list of extra ``TestCase`` instances to add to the
suite that is executed by the test runner. These extra tests are run
@@ -282,13 +293,13 @@ Methods
This method should return the number of tests that failed.
-.. method:: DjangoTestSuiteRunner.setup_test_environment(**kwargs)
+.. method:: DiscoverRunner.setup_test_environment(**kwargs)
Sets up the test environment by calling
:func:`~django.test.utils.setup_test_environment` and setting
:setting:`DEBUG` to ``False``.
-.. method:: DjangoTestSuiteRunner.build_suite(test_labels, extra_tests=None, **kwargs)
+.. method:: DiscoverRunner.build_suite(test_labels, extra_tests=None, **kwargs)
Constructs a test suite that matches the test labels provided.
@@ -309,7 +320,7 @@ Methods
Returns a ``TestSuite`` instance ready to be run.
-.. method:: DjangoTestSuiteRunner.setup_databases(**kwargs)
+.. method:: DiscoverRunner.setup_databases(**kwargs)
Creates the test databases.
@@ -317,13 +328,13 @@ Methods
that have been made. This data will be provided to the ``teardown_databases()``
function at the conclusion of testing.
-.. method:: DjangoTestSuiteRunner.run_suite(suite, **kwargs)
+.. method:: DiscoverRunner.run_suite(suite, **kwargs)
Runs the test suite.
Returns the result produced by the running the test suite.
-.. method:: DjangoTestSuiteRunner.teardown_databases(old_config, **kwargs)
+.. method:: DiscoverRunner.teardown_databases(old_config, **kwargs)
Destroys the test databases, restoring pre-test conditions.
@@ -331,11 +342,11 @@ Methods
database configuration that need to be reversed. It is the return
value of the ``setup_databases()`` method.
-.. method:: DjangoTestSuiteRunner.teardown_test_environment(**kwargs)
+.. method:: DiscoverRunner.teardown_test_environment(**kwargs)
Restores the pre-test environment.
-.. method:: DjangoTestSuiteRunner.suite_result(suite, result, **kwargs)
+.. method:: DiscoverRunner.suite_result(suite, result, **kwargs)
Computes and returns a return code based on a test suite, and the result
from that test suite.
@@ -402,7 +413,7 @@ can be useful during testing.
``old_database_name``.
The ``verbosity`` argument has the same behavior as for
- :class:`~django.test.simple.DjangoTestSuiteRunner`.
+ :class:`~django.test.runner.DiscoverRunner`.
.. _topics-testing-code-coverage:
diff --git a/docs/topics/testing/doctests.txt b/docs/topics/testing/doctests.txt
deleted file mode 100644
index 5036e946a9..0000000000
--- a/docs/topics/testing/doctests.txt
+++ /dev/null
@@ -1,81 +0,0 @@
-===================
-Django and doctests
-===================
-
-Doctests use Python's standard :mod:`doctest` module, which searches your
-docstrings for statements that resemble a session of the Python interactive
-interpreter. A full explanation of how :mod:`doctest` works is out of the scope
-of this document; read Python's official documentation for the details.
-
-.. admonition:: What's a **docstring**?
-
- A good explanation of docstrings (and some guidelines for using them
- effectively) can be found in :pep:`257`:
-
- A docstring is a string literal that occurs as the first statement in
- a module, function, class, or method definition. Such a docstring
- becomes the ``__doc__`` special attribute of that object.
-
- For example, this function has a docstring that describes what it does::
-
- def add_two(num):
- "Return the result of adding two to the provided number."
- return num + 2
-
- Because tests often make great documentation, putting tests directly in
- your docstrings is an effective way to document *and* test your code.
-
-As with unit tests, for a given Django application, the test runner looks for
-doctests in two places:
-
-* The ``models.py`` file. You can define module-level doctests and/or a
- doctest for individual models. It's common practice to put
- application-level doctests in the module docstring and model-level
- doctests in the model docstrings.
-
-* A file called ``tests.py`` in the application directory -- i.e., the
- directory that holds ``models.py``. This file is a hook for any and all
- doctests you want to write that aren't necessarily related to models.
-
-This example doctest is equivalent to the example given in the unittest section
-above::
-
- # models.py
-
- from django.db import models
-
- class Animal(models.Model):
- """
- An animal that knows how to make noise
-
- # Create some animals
- >>> lion = Animal.objects.create(name="lion", sound="roar")
- >>> cat = Animal.objects.create(name="cat", sound="meow")
-
- # Make 'em speak
- >>> lion.speak()
- 'The lion says "roar"'
- >>> cat.speak()
- 'The cat says "meow"'
- """
- name = models.CharField(max_length=20)
- sound = models.CharField(max_length=20)
-
- def speak(self):
- return 'The %s says "%s"' % (self.name, self.sound)
-
-When you :ref:`run your tests <running-tests>`, the test runner will find this
-docstring, notice that portions of it look like an interactive Python session,
-and execute those lines while checking that the results match.
-
-In the case of model tests, note that the test runner takes care of creating
-its own test database. That is, any test that accesses a database -- by
-creating and saving model instances, for example -- will not affect your
-production database. However, the database is not refreshed between doctests,
-so if your doctest requires a certain state you should consider flushing the
-database or loading a fixture. (See the section on :ref:`fixtures
-<topics-testing-fixtures>` for more on this.) Note that to use this feature,
-the database user Django is connecting as must have ``CREATE DATABASE``
-rights.
-
-For more details about :mod:`doctest`, see the Python documentation.
diff --git a/docs/topics/testing/index.txt b/docs/topics/testing/index.txt
index 94e88bdf04..1a99a399b4 100644
--- a/docs/topics/testing/index.txt
+++ b/docs/topics/testing/index.txt
@@ -6,7 +6,6 @@ Testing in Django
:hidden:
overview
- doctests
advanced
Automated testing is an extremely useful bug-killing tool for the modern
@@ -29,83 +28,13 @@ it should be doing.
The best part is, it's really easy.
-Unit tests v. doctests
-======================
-
-There are two primary ways to write tests with Django, corresponding to the
-two test frameworks that ship in the Python standard library. The two
-frameworks are:
-
-* **Unit tests** -- tests that are expressed as methods on a Python class
- that subclasses :class:`unittest.TestCase` or Django's customized
- :class:`~django.test.TestCase`. For example::
-
- import unittest
-
- class MyFuncTestCase(unittest.TestCase):
- def testBasic(self):
- a = ['larry', 'curly', 'moe']
- self.assertEqual(my_func(a, 0), 'larry')
- self.assertEqual(my_func(a, 1), 'curly')
-
-* **Doctests** -- tests that are embedded in your functions' docstrings and
- are written in a way that emulates a session of the Python interactive
- interpreter. For example::
-
- def my_func(a_list, idx):
- """
- >>> a = ['larry', 'curly', 'moe']
- >>> my_func(a, 0)
- 'larry'
- >>> my_func(a, 1)
- 'curly'
- """
- return a_list[idx]
-
-Which should I use?
--------------------
-
-Because Django supports both of the standard Python test frameworks, it's up to
-you and your tastes to decide which one to use. You can even decide to use
-*both*.
-
-For developers new to testing, however, this choice can seem confusing. Here,
-then, are a few key differences to help you decide which approach is right for
-you:
-
-* If you've been using Python for a while, :mod:`doctest` will probably feel
- more "pythonic". It's designed to make writing tests as easy as possible,
- so it requires no overhead of writing classes or methods. You simply put
- tests in docstrings. This has the added advantage of serving as
- documentation (and correct documentation, at that!). However, while
- doctests are good for some simple example code, they are not very good if
- you want to produce either high quality, comprehensive tests or high
- quality documentation. Test failures are often difficult to debug
- as it can be unclear exactly why the test failed. Thus, doctests should
- generally be avoided and used primarily for documentation examples only.
-
-* The :mod:`unittest` framework will probably feel very familiar to
- developers coming from Java. :mod:`unittest` is inspired by Java's JUnit,
- so you'll feel at home with this method if you've used JUnit or any test
- framework inspired by JUnit.
-
-* If you need to write a bunch of tests that share similar code, then
- you'll appreciate the :mod:`unittest` framework's organization around
- classes and methods. This makes it easy to abstract common tasks into
- common methods. The framework also supports explicit setup and/or cleanup
- routines, which give you a high level of control over the environment
- in which your test cases are run.
-
-* If you're writing tests for Django itself, you should use :mod:`unittest`.
-
Where to go from here
=====================
-As unit tests are preferred in Django, we treat them in detail in the
+The preferred way to write tests in Django is using the :mod:`unittest` module
+built in to the Python standard library. This is covered in detail in the
:doc:`overview` document.
-:doc:`doctests` describes Django-specific features when using doctests.
-
-You can also use any *other* Python test framework, Django provides an API and
+You can also use any *other* Python test framework; Django provides an API and
tools for that kind of integration. They are described in the
:ref:`other-testing-frameworks` section of :doc:`advanced`.
diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt
index 9228a07b31..fc2b393898 100644
--- a/docs/topics/testing/overview.txt
+++ b/docs/topics/testing/overview.txt
@@ -17,7 +17,7 @@ Writing tests
=============
Django's unit tests use a Python standard library module: :mod:`unittest`. This
-module defines tests in class-based approach.
+module defines tests using a class-based approach.
.. admonition:: unittest2
@@ -46,46 +46,37 @@ module defines tests in class-based approach.
.. _unittest2: http://pypi.python.org/pypi/unittest2
-For a given Django application, the test runner looks for unit tests in two
-places:
+Here is an example which subclasses from :class:`django.test.TestCase`,
+which is a subclass of :class:`unittest.TestCase` that runs each test inside a
+transaction to provide isolation::
-* The ``models.py`` file. The test runner looks for any subclass of
- :class:`unittest.TestCase` in this module.
-
-* A file called ``tests.py`` in the application directory -- i.e., the
- directory that holds ``models.py``. Again, the test runner looks for any
- subclass of :class:`unittest.TestCase` in this module.
-
-Here is an example :class:`unittest.TestCase` subclass::
-
- from django.utils import unittest
+ from django.test import TestCase
from myapp.models import Animal
- class AnimalTestCase(unittest.TestCase):
+ class AnimalTestCase(TestCase):
def setUp(self):
- self.lion = Animal(name="lion", sound="roar")
- self.cat = Animal(name="cat", sound="meow")
+ Animal.objects.create(name="lion", sound="roar")
+ Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
- self.assertEqual(self.lion.speak(), 'The lion says "roar"')
- self.assertEqual(self.cat.speak(), 'The cat says "meow"')
+ lion = Animal.objects.get(name="lion")
+ cat = Animal.objects.get(name="cat")
+ self.assertEqual(lion.speak(), 'The lion says "roar"')
+ self.assertEqual(cat.speak(), 'The cat says "meow"')
-When you :ref:`run your tests <running-tests>`, the default behavior of the test
-utility is to find all the test cases (that is, subclasses of
-:class:`unittest.TestCase`) in ``models.py`` and ``tests.py``, automatically
-build a test suite out of those test cases, and run that suite.
+When you :ref:`run your tests <running-tests>`, the default behavior of the
+test utility is to find all the test cases (that is, subclasses of
+:class:`unittest.TestCase`) in any file whose name begins with ``test``,
+automatically build a test suite out of those test cases, and run that suite.
-There is a second way to define the test suite for a module: if you define a
-function called ``suite()`` in either ``models.py`` or ``tests.py``, the
-Django test runner will use that function to construct the test suite for that
-module. This follows the `suggested organization`_ for unit tests. See the
-Python documentation for more details on how to construct a complex test
-suite.
+.. versionchanged:: 1.6
-For more details about :mod:`unittest`, see the Python documentation.
+ Previously, Django's default test runner only discovered tests in
+ ``tests.py`` and ``models.py`` files within a Python package listed in
+ :setting:`INSTALLED_APPS`.
-.. _suggested organization: http://docs.python.org/library/unittest.html#organizing-tests
+For more details about :mod:`unittest`, see the Python documentation.
.. warning::
@@ -93,14 +84,15 @@ For more details about :mod:`unittest`, see the Python documentation.
be sure to create your test classes as subclasses of
:class:`django.test.TestCase` rather than :class:`unittest.TestCase`.
- In the example above, we instantiate some models but do not save them to
- the database. Using :class:`unittest.TestCase` avoids the cost of running
- each test in a transaction and flushing the database, but for most
- applications the scope of tests you will be able to write this way will
- be fairly limited, so it's easiest to use :class:`django.test.TestCase`.
+ Using :class:`unittest.TestCase` avoids the cost of running each test in a
+ transaction and flushing the database, but if your tests interact with
+ the database their behavior will vary based on the order that the test
+ runner executes them. This can lead to unit tests that pass when run in
+ isolation but fail when run in a suite.
.. _running-tests:
+
Running tests
=============
@@ -109,46 +101,47 @@ your project's ``manage.py`` utility::
$ ./manage.py test
-By default, this will run every test in every application in
-:setting:`INSTALLED_APPS`. If you only want to run tests for a particular
-application, add the application name to the command line. For example, if your
-:setting:`INSTALLED_APPS` contains ``'myproject.polls'`` and
-``'myproject.animals'``, you can run the ``myproject.animals`` unit tests alone
-with this command::
+Test discovery is based on the unittest module's `built-in test discovery`. By
+default, this will discover tests in any file named "test*.py" under the
+current working directory.
- $ ./manage.py test animals
+.. _built-in test discovery: http://docs.python.org/2/library/unittest.html#test-discovery
-Note that we used ``animals``, not ``myproject.animals``.
+You can specify particular tests to run by supplying any number of "test
+labels" to ``./manage.py test``. Each test label can be a full Python dotted
+path to a package, module, ``TestCase`` subclass, or test method. For instance::
-You can be even *more* specific by naming an individual test case. To
-run a single test case in an application (for example, the
-``AnimalTestCase`` described in the "Writing unit tests" section), add
-the name of the test case to the label on the command line::
+ # Run all the tests in the animals.tests module
+ $ ./manage.py test animals.tests
+
+ # Run all the tests found within the 'animals' package
+ $ ./manage.py test animals
- $ ./manage.py test animals.AnimalTestCase
+ # Run just one test case
+ $ ./manage.py test animals.tests.AnimalTestCase
-And it gets even more granular than that! To run a *single* test
-method inside a test case, add the name of the test method to the
-label::
+ # Run just one test method
+ $ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak
- $ ./manage.py test animals.AnimalTestCase.test_animals_can_speak
+You can also provide a path to a directory to discover tests below that
+directory::
-You can use the same rules if you're using doctests. Django will use the
-test label as a path to the test method or class that you want to run.
-If your ``models.py`` or ``tests.py`` has a function with a doctest, or
-class with a class-level doctest, you can invoke that test by appending the
-name of the test method or class to the label::
+ $ ./manage.py test animals/
- $ ./manage.py test animals.classify
+You can specify a custom filename pattern match using the ``-p`` (or
+``--pattern``) option, if your test files are named differently from the
+``test*.py`` pattern::
-If you want to run the doctest for a specific method in a class, add the
-name of the method to the label::
+ $ ./manage.py test --pattern="tests_*.py"
- $ ./manage.py test animals.Classifier.run
+.. versionchanged:: 1.6
-If you're using a ``__test__`` dictionary to specify doctests for a
-module, Django will use the label as a key in the ``__test__`` dictionary
-for defined in ``models.py`` and ``tests.py``.
+ Previously, test labels were in the form ``applabel``,
+ ``applabel.TestCase``, or ``applabel.TestCase.test_method``, rather than
+ being true Python dotted paths, and tests could only be found within
+ ``tests.py`` or ``models.py`` files within a Python package listed in
+ :setting:`INSTALLED_APPS`. The ``--pattern`` option and file paths as test
+ labels are new in 1.6.
If you press ``Ctrl-C`` while the tests are running, the test runner will
wait for the currently running test to complete and then exit gracefully.
@@ -173,6 +166,7 @@ be reported, and any test databases created by the run will not be destroyed.
flag areas in your code that aren't strictly wrong but could benefit
from a better implementation.
+
.. _the-test-database:
The test database
@@ -290,25 +284,15 @@ If there are test failures, however, you'll see full details about which tests
failed::
======================================================================
- FAIL: Doctest: ellington.core.throttle.models
+ FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
- File "/dev/django/test/doctest.py", line 2153, in runTest
- raise self.failureException(self.format_failure(new.getvalue()))
- AssertionError: Failed doctest test for myapp.models
- File "/dev/myapp/models.py", line 0, in models
-
- ----------------------------------------------------------------------
- File "/dev/myapp/models.py", line 14, in myapp.models
- Failed example:
- throttle.check("actor A", "action one", limit=2, hours=1)
- Expected:
- True
- Got:
- False
+ File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
+ self.assertEqual(future_poll.was_published_recently(), False)
+ AssertionError: True != False
----------------------------------------------------------------------
- Ran 2 tests in 0.048s
+ Ran 1 test in 0.003s
FAILED (failures=1)