summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2013-06-19 12:03:20 +0100
committerAndrew Godwin <andrew@aeracode.org>2013-06-19 12:05:23 +0100
commit9daf81b94e7945d7adfdf62206cf9cb436166f0d (patch)
tree0ca2a77977432d0c139886297afb433569b588ca /docs
parent315ab41e416c777d4f42932d42df07872e8f8895 (diff)
parentd9a43545be1af95a13c181c8b178f5631d3a4148 (diff)
Merge remote-tracking branch 'core/master' into schema-alteration
Conflicts: django/db/models/loading.py
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile3
-rw-r--r--docs/conf.py3
-rw-r--r--docs/howto/deployment/wsgi/index.txt8
-rw-r--r--docs/howto/deployment/wsgi/uwsgi.txt9
-rw-r--r--docs/internals/committers.txt11
-rw-r--r--docs/internals/contributing/writing-code/submitting-patches.txt4
-rw-r--r--docs/intro/tutorial03.txt7
-rw-r--r--docs/ref/class-based-views/base.txt15
-rw-r--r--docs/ref/class-based-views/generic-date-based.txt24
-rw-r--r--docs/ref/class-based-views/generic-display.txt29
-rw-r--r--docs/ref/class-based-views/generic-editing.txt49
-rw-r--r--docs/ref/contrib/admin/index.txt14
-rw-r--r--docs/ref/contrib/auth.txt16
-rw-r--r--docs/ref/contrib/flatpages.txt12
-rw-r--r--docs/ref/contrib/formtools/form-wizard.txt2
-rw-r--r--docs/ref/django-admin.txt13
-rw-r--r--docs/ref/forms/api.txt32
-rw-r--r--docs/ref/forms/models.txt29
-rw-r--r--docs/ref/forms/validation.txt110
-rw-r--r--docs/ref/forms/widgets.txt5
-rw-r--r--docs/ref/models/instances.txt14
-rw-r--r--docs/ref/settings.txt4
-rw-r--r--docs/ref/signals.txt19
-rw-r--r--docs/ref/templates/builtins.txt4
-rw-r--r--docs/ref/utils.txt2
-rw-r--r--docs/releases/1.5.txt10
-rw-r--r--docs/releases/1.6.txt97
-rw-r--r--docs/topics/auth/customizing.txt18
-rw-r--r--docs/topics/auth/passwords.txt6
-rw-r--r--docs/topics/class-based-views/mixins.txt6
-rw-r--r--docs/topics/files.txt6
-rw-r--r--docs/topics/forms/formsets.txt22
-rw-r--r--docs/topics/forms/index.txt16
-rw-r--r--docs/topics/forms/media.txt2
-rw-r--r--docs/topics/forms/modelforms.txt61
-rw-r--r--docs/topics/settings.txt5
-rw-r--r--docs/topics/testing/advanced.txt74
-rw-r--r--docs/topics/testing/overview.txt52
38 files changed, 672 insertions, 141 deletions
diff --git a/docs/Makefile b/docs/Makefile
index 2a8bcd7101..a2c926c7ea 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -6,11 +6,12 @@ SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
+LANGUAGE =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees -D language=$(LANGUAGE) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
diff --git a/docs/conf.py b/docs/conf.py
index a01ddb60b8..feff99b6f4 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -77,6 +77,9 @@ django_next_version = '1.6'
# for a list of supported languages.
#language = None
+# Location for .po/.mo translation files used when language is set
+locale_dirs = ['locale/']
+
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
diff --git a/docs/howto/deployment/wsgi/index.txt b/docs/howto/deployment/wsgi/index.txt
index ad32366bf8..17eb53cf0c 100644
--- a/docs/howto/deployment/wsgi/index.txt
+++ b/docs/howto/deployment/wsgi/index.txt
@@ -82,6 +82,14 @@ to combine a Django application with a WSGI application of another framework.
.. _`WSGI middleware`: http://www.python.org/dev/peps/pep-3333/#middleware-components-that-play-both-sides
+.. note::
+
+ Some third-party WSGI middleware do not call ``close`` on the response
+ object after handling a request — most notably Sentry's error reporting
+ middleware up to version 2.0.7. In those cases the
+ :data:`~django.core.signals.request_finished` signal isn't sent. This can
+ result in idle connections to database and memcache servers.
+
Upgrading from Django < 1.4
---------------------------
diff --git a/docs/howto/deployment/wsgi/uwsgi.txt b/docs/howto/deployment/wsgi/uwsgi.txt
index 22f39342d6..3e9b47e8f9 100644
--- a/docs/howto/deployment/wsgi/uwsgi.txt
+++ b/docs/howto/deployment/wsgi/uwsgi.txt
@@ -34,6 +34,15 @@ command. For example:
.. _installation procedures: http://projects.unbit.it/uwsgi/wiki/Install
+.. warning::
+
+ Some distributions, including Debian and Ubuntu, ship an outdated version
+ of uWSGI that does not conform to the WSGI specification. Versions prior to
+ 1.2.6 do not call ``close`` on the response object after handling a
+ request. In those cases the :data:`~django.core.signals.request_finished`
+ signal isn't sent. This can result in idle connections to database and
+ memcache servers.
+
uWSGI model
-----------
diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt
index b56c8e469b..6732f1561f 100644
--- a/docs/internals/committers.txt
+++ b/docs/internals/committers.txt
@@ -526,6 +526,17 @@ Marc Tamlyn
.. _CCBV: http://ccbv.co.uk/
.. _Incuna Ltd: http://incuna.com/
+Baptiste Mispelon
+ Baptiste discovered Django around the 1.2 version and promptly switched away
+ from his homegrown PHP framework. He started getting more involved in the
+ project after attending DjangoCon EU 2012, mostly by triaging tickets and
+ submitting small patches.
+
+ Baptiste currently lives in Budapest, Hungary and works for `M2BPO`_,
+ a small French company providing services to architects.
+
+.. _M2BPO: http://www.m2bpo.fr
+
Developers Emeritus
===================
diff --git a/docs/internals/contributing/writing-code/submitting-patches.txt b/docs/internals/contributing/writing-code/submitting-patches.txt
index ed8aad99b3..8f8ddddab4 100644
--- a/docs/internals/contributing/writing-code/submitting-patches.txt
+++ b/docs/internals/contributing/writing-code/submitting-patches.txt
@@ -37,7 +37,7 @@ and time availability), claim it by following these steps:
`ticket tracker`_.
* If a ticket for this issue already exists, make sure nobody else has
- claimed it. To do this, look at the "Assigned to" section of the ticket.
+ claimed it. To do this, look at the "Owned by" section of the ticket.
If it's assigned to "nobody," then it's available to be claimed.
Otherwise, somebody else is working on this ticket, and you either find
another bug/feature to work on, or contact the developer working on the
@@ -48,7 +48,7 @@ and time availability), claim it by following these steps:
* Claim the ticket:
- 1. click the "accept" radio button under "Action" near the bottom of the
+ 1. click the "assign to myself" radio button under "Action" near the bottom of the
page,
2. then click "Submit changes."
diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt
index 120369172e..6193ec45f7 100644
--- a/docs/intro/tutorial03.txt
+++ b/docs/intro/tutorial03.txt
@@ -473,6 +473,13 @@ template for all 404 errors when :setting:`DEBUG` is set to ``False`` (in your
settings module). If you do create the template, add at least some dummy
content like "Page not found".
+.. warning::
+
+ If :setting:`DEBUG` is set to ``False``, all responses will be
+ "Bad Request (400)" unless you specify the proper :setting:`ALLOWED_HOSTS`
+ as well (something like ``['localhost', '127.0.0.1']`` for
+ local development).
+
A couple more things to note about 404 views:
* If :setting:`DEBUG` is set to ``True`` (in your settings module) then your
diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt
index 319bd4ebfe..4ad017c342 100644
--- a/docs/ref/class-based-views/base.txt
+++ b/docs/ref/class-based-views/base.txt
@@ -192,22 +192,24 @@ RedirectView
permanent = False
query_string = True
+ pattern_name = 'article-detail'
- def get_redirect_url(self, pk):
+ def get_redirect_url(self, *args, **kwargs):
article = get_object_or_404(Article, pk=pk)
article.update_counter()
- return reverse('product_detail', args=(pk,))
+ return super(ArticleCounterRedirectView, self).get_redirect_url(*args, **kwargs)
**Example urls.py**::
from django.conf.urls import patterns, url
from django.views.generic.base import RedirectView
- from article.views import ArticleCounterRedirectView
+ from article.views import ArticleCounterRedirectView, ArticleDetail
urlpatterns = patterns('',
- url(r'^(?P<pk>\d+)/$', ArticleCounterRedirectView.as_view(), name='article-counter'),
+ url(r'^counter/(?P<pk>\d+)/$', ArticleCounterRedirectView.as_view(), name='article-counter'),
+ url(r'^details/(?P<pk>\d+)/$', ArticleDetail.as_view(), name='article-detail'),
url(r'^go-to-django/$', RedirectView.as_view(url='http://djangoproject.com'), name='go-to-django'),
)
@@ -218,6 +220,11 @@ RedirectView
The URL to redirect to, as a string. Or ``None`` to raise a 410 (Gone)
HTTP error.
+ .. attribute:: pattern_name
+
+ The name of the URL pattern to redirect to. Reversing will be done
+ using the same args and kwargs as are passed in for this view.
+
.. attribute:: permanent
Whether the redirect should be permanent. The only difference here is
diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt
index 1ebee254b1..205d556463 100644
--- a/docs/ref/class-based-views/generic-date-based.txt
+++ b/docs/ref/class-based-views/generic-date-based.txt
@@ -63,7 +63,7 @@ ArchiveIndexView
month or day using the attribute ``date_list_period``. This also applies
to all subclass views.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.conf.urls import patterns, url
from django.views.generic.dates import ArchiveIndexView
@@ -160,7 +160,7 @@ YearArchiveView
* Uses a default ``template_name_suffix`` of ``_archive_year``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.dates import YearArchiveView
@@ -172,7 +172,7 @@ YearArchiveView
make_object_list = True
allow_future = True
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -255,7 +255,7 @@ MonthArchiveView
* Uses a default ``template_name_suffix`` of ``_archive_month``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.dates import MonthArchiveView
@@ -267,7 +267,7 @@ MonthArchiveView
make_object_list = True
allow_future = True
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -348,7 +348,7 @@ WeekArchiveView
* Uses a default ``template_name_suffix`` of ``_archive_week``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.dates import WeekArchiveView
@@ -361,7 +361,7 @@ WeekArchiveView
week_format = "%W"
allow_future = True
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -463,7 +463,7 @@ DayArchiveView
* Uses a default ``template_name_suffix`` of ``_archive_day``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.dates import DayArchiveView
@@ -475,7 +475,7 @@ DayArchiveView
make_object_list = True
allow_future = True
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -537,7 +537,7 @@ TodayArchiveView
* Uses a default ``template_name_suffix`` of ``_archive_today``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.dates import TodayArchiveView
@@ -549,7 +549,7 @@ TodayArchiveView
make_object_list = True
allow_future = True
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -599,7 +599,7 @@ DateDetailView
* Uses a default ``template_name_suffix`` of ``_detail``.
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
from django.views.generic.dates import DateDetailView
diff --git a/docs/ref/class-based-views/generic-display.txt b/docs/ref/class-based-views/generic-display.txt
index c133134d65..7fc95ac5d2 100644
--- a/docs/ref/class-based-views/generic-display.txt
+++ b/docs/ref/class-based-views/generic-display.txt
@@ -36,7 +36,7 @@ DetailView
9. ``get()``
10. :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response()`
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.detail import DetailView
from django.utils import timezone
@@ -52,7 +52,7 @@ DetailView
context['now'] = timezone.now()
return context
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -62,6 +62,16 @@ DetailView
url(r'^(?P<slug>[-_\w]+)/$', ArticleDetailView.as_view(), name='article-detail'),
)
+ **Example myapp/article_detail.html**:
+
+ .. code-block:: html+django
+
+ <h1>{{ object.headline }}</h1>
+ <p>{{ object.content }}</p>
+ <p>Reporter: {{ object.reporter }}</p>
+ <p>Published: {{ object.pub_date|date }}</p>
+ <p>Date: {{ object.now|date }}</p>
+
ListView
--------
@@ -111,7 +121,7 @@ ListView
context['now'] = timezone.now()
return context
- **Example urls.py**::
+ **Example myapp/urls.py**::
from django.conf.urls import patterns, url
@@ -121,6 +131,19 @@ ListView
url(r'^$', ArticleListView.as_view(), name='article-list'),
)
+ **Example myapp/article_list.html**:
+
+ .. code-block:: html+django
+
+ <h1>Articles</h1>
+ <ul>
+ {% for article in object_list %}
+ <li>{{ article.pub_date|date }} - {{ article.headline }}</li>
+ {% empty %}
+ <li>No articles yet.</li>
+ {% endfor %}
+ </ul>
+
.. class:: django.views.generic.list.BaseListView
A base view for displaying a list of objects. It is not intended to be used
diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt
index c1fb2dcca9..51dfe7c71b 100644
--- a/docs/ref/class-based-views/generic-editing.txt
+++ b/docs/ref/class-based-views/generic-editing.txt
@@ -42,7 +42,7 @@ FormView
* :class:`django.views.generic.edit.ProcessFormView`
* :class:`django.views.generic.base.View`
- **Example forms.py**::
+ **Example myapp/forms.py**::
from django import forms
@@ -54,7 +54,7 @@ FormView
# send email using the self.cleaned_data dictionary
pass
- **Example views.py**::
+ **Example myapp/views.py**::
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
@@ -70,6 +70,16 @@ FormView
form.send_email()
return super(ContactView, self).form_valid(form)
+ **Example myapp/contact.html**:
+
+ .. code-block:: html+django
+
+ <form action="" method="post">{% csrf_token %}
+ {{ form.as_p }}
+ <input type="submit" value="Send message" />
+ </form>
+
+
CreateView
----------
@@ -101,7 +111,7 @@ CreateView
creating objects for the example ``Author`` model would cause the
default ``template_name`` to be ``'myapp/author_create_form.html'``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.edit import CreateView
from myapp.models import Author
@@ -110,6 +120,15 @@ CreateView
model = Author
fields = ['name']
+ **Example myapp/author_form.html**:
+
+ .. code-block:: html+django
+
+ <form action="" method="post">{% csrf_token %}
+ {{ form.as_p }}
+ <input type="submit" value="Create" />
+ </form>
+
UpdateView
----------
@@ -143,7 +162,7 @@ UpdateView
updating objects for the example ``Author`` model would cause the
default ``template_name`` to be ``'myapp/author_update_form.html'``.
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.edit import UpdateView
from myapp.models import Author
@@ -151,6 +170,16 @@ UpdateView
class AuthorUpdate(UpdateView):
model = Author
fields = ['name']
+ template_name_suffix = '_update_form'
+
+ **Example myapp/author_update_form.html**:
+
+ .. code-block:: html+django
+
+ <form action="" method="post">{% csrf_token %}
+ {{ form.as_p }}
+ <input type="submit" value="Update" />
+ </form>
DeleteView
----------
@@ -184,8 +213,7 @@ DeleteView
deleting objects for the example ``Author`` model would cause the
default ``template_name`` to be ``'myapp/author_check_delete.html'``.
-
- **Example views.py**::
+ **Example myapp/views.py**::
from django.views.generic.edit import DeleteView
from django.core.urlresolvers import reverse_lazy
@@ -194,3 +222,12 @@ DeleteView
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
+
+ **Example myapp/author_confirm_delete.html**:
+
+ .. code-block:: html+django
+
+ <form action="" method="post">{% csrf_token %}
+ <p>Are you sure you want to delete "{{ object }}"?</p>
+ <input type="submit" value="Confirm" />
+ </form>
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 7377f11a63..90ef68837a 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -870,6 +870,14 @@ subclass::
``prepopulated_fields`` doesn't accept ``DateTimeField``, ``ForeignKey``,
nor ``ManyToManyField`` fields.
+.. attribute:: ModelAdmin.preserve_filters
+
+ .. versionadded:: 1.6
+
+ The admin now preserves filters on the list view after creating, editing
+ or deleting an object. You can restore the previous behavior of clearing
+ filters by setting this attribute to ``False``.
+
.. attribute:: ModelAdmin.radio_fields
By default, Django's admin uses a select-box interface (<select>) for
@@ -2269,9 +2277,9 @@ your URLconf. Specifically, add these four patterns:
.. code-block:: python
url(r'^admin/password_reset/$', 'django.contrib.auth.views.password_reset', name='admin_password_reset'),
- (r'^admin/password_reset/done/$', 'django.contrib.auth.views.password_reset_done'),
- (r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm'),
- (r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete'),
+ url(r'^admin/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', name='password_reset_done'),
+ url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'),
+ url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete'),
(This assumes you've added the admin at ``admin/`` and requires that you put
the URLs starting with ``^admin/`` before the line that includes the admin app
diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt
index 40b3629f63..afbc6ec048 100644
--- a/docs/ref/contrib/auth.txt
+++ b/docs/ref/contrib/auth.txt
@@ -132,12 +132,28 @@ Methods
password hashing. Doesn't save the
:class:`~django.contrib.auth.models.User` object.
+ When the ``raw_password`` is ``None``, the password will be set to an
+ unusable password, as if
+ :meth:`~django.contrib.auth.models.User.set_unusable_password()`
+ were used.
+
+ .. versionchanged:: 1.6
+
+ In Django 1.4 and 1.5, a blank string was unintentionally stored
+ as an unsable password.
+
.. method:: check_password(raw_password)
Returns ``True`` if the given raw string is the correct password for
the user. (This takes care of the password hashing in making the
comparison.)
+ .. versionchanged:: 1.6
+
+ In Django 1.4 and 1.5, a blank string was unintentionally
+ considered to be an unusable password, resulting in this method
+ returning ``False`` for such a password.
+
.. method:: set_unusable_password()
Marks the user as having no password set. This isn't the same as
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index 292b304acb..11d74d75c3 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -47,7 +47,7 @@ Then either:
3. Add an entry in your URLconf. For example::
urlpatterns = patterns('',
- ('^pages/', include('django.contrib.flatpages.urls')),
+ (r'^pages/', include('django.contrib.flatpages.urls')),
)
or:
@@ -74,7 +74,7 @@ There are several ways to include the flat pages in your URLconf. You can
dedicate a particular path to flat pages::
urlpatterns = patterns('',
- ('^pages/', include('django.contrib.flatpages.urls')),
+ (r'^pages/', include('django.contrib.flatpages.urls')),
)
You can also set it up as a "catchall" pattern. In this case, it is important
@@ -82,9 +82,15 @@ to place the pattern at the end of the other urlpatterns::
# Your other patterns here
urlpatterns += patterns('django.contrib.flatpages.views',
- (r'^(?P<url>.*)$', 'flatpage'),
+ (r'^(?P<url>.*/)$', 'flatpage'),
)
+.. warning::
+
+ If you set :setting:`APPEND_SLASH` to ``False``, you must remove the slash
+ in the catchall pattern or flatpages without a trailing slash will not be
+ matched.
+
Another common setup is to use flat pages for a limited set of known pages and
to hard code the urls, so you can reference them with the :ttag:`url` template
tag::
diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt
index 7795a32c09..ca11aef763 100644
--- a/docs/ref/contrib/formtools/form-wizard.txt
+++ b/docs/ref/contrib/formtools/form-wizard.txt
@@ -166,7 +166,7 @@ This template expects a ``wizard`` object that has various items attached to
it:
* ``form`` -- The :class:`~django.forms.Form` or
- :class:`~django.forms.formset.BaseFormSet` instance for the current step
+ :class:`~django.forms.formsets.BaseFormSet` instance for the current step
(either empty or with errors).
* ``steps`` -- A helper object to access the various steps related data:
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index e21e3d2766..c2c11e6db4 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -89,6 +89,19 @@ documentation for the :djadminopt:`--verbosity` option.
Available commands
==================
+checksetup
+----------
+
+.. django-admin:: checksetup
+
+.. versionadded:: 1.6
+
+Performs a series of checks to verify a given setup (settings/application code)
+is compatible with the current version of Django.
+
+Upon finding things that are incompatible or require notifying the user, it
+issues a series of warnings.
+
cleanup
-------
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 67e3aab712..3c17827800 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -498,6 +498,8 @@ include ``%s`` -- then the library will act as if ``auto_id`` is ``True``.
By default, ``auto_id`` is set to the string ``'id_%s'``.
+.. attribute:: Form.label_suffix
+
Normally, a colon (``:``) will be appended after any label name when a form is
rendered. It's possible to change the colon to another character, or omit it
entirely, using the ``label_suffix`` parameter::
@@ -650,12 +652,17 @@ To separately render the label tag of a form field, you can call its
>>> f = ContactForm(data)
>>> print(f['message'].label_tag())
- <label for="id_message">Message</label>
+ <label for="id_message">Message:</label>
Optionally, you can provide the ``contents`` parameter which will replace the
auto-generated label tag. An optional ``attrs`` dictionary may contain
additional attributes for the ``<label>`` tag.
+.. versionchanged:: 1.6
+
+ The label now includes the form's :attr:`~django.forms.Form.label_suffix`
+ (a semicolon, by default).
+
.. method:: BoundField.css_classes()
When you use Django's rendering shortcuts, CSS classes are used to
@@ -688,6 +695,29 @@ by a ``Widget``::
>>> print(bound_form['subject'].value())
hi
+.. attribute:: BoundField.id_for_label
+
+Use this property to render the ID of this field. For example, if you are
+manually constructing a ``<label>`` in your template (despite the fact that
+:meth:`~BoundField.label_tag` will do this for you):
+
+.. code-block:: html+django
+
+ <label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
+
+By default, this will be the field's name prefixed by ``id_``
+("``id_my_field``" for the example above). You may modify the ID by setting
+:attr:`~django.forms.Widget.attrs` on the field's widget. For example,
+declaring a field like this::
+
+ my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))
+
+and using the template above, would render something like:
+
+.. code-block:: html
+
+ <label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" />
+
.. _binding-uploaded-files:
Binding uploaded files to a form
diff --git a/docs/ref/forms/models.txt b/docs/ref/forms/models.txt
index b54056af0c..840a896d75 100644
--- a/docs/ref/forms/models.txt
+++ b/docs/ref/forms/models.txt
@@ -5,7 +5,7 @@ Model Form Functions
.. module:: django.forms.models
:synopsis: Django's functions for building model forms and formsets.
-.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None, widgets=None, localized_fields=None)
+.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None, widgets=None, localized_fields=None, labels=None, help_texts=None, error_messages=None)
Returns a :class:`~django.forms.ModelForm` class for the given ``model``.
You can optionally pass a ``form`` argument to use as a starting point for
@@ -20,11 +20,18 @@ Model Form Functions
``widgets`` is a dictionary of model field names mapped to a widget.
- ``localized_fields`` is a list of names of fields which should be localized.
-
``formfield_callback`` is a callable that takes a model field and returns
a form field.
+ ``localized_fields`` is a list of names of fields which should be localized.
+
+ ``labels`` is a dictionary of model field names mapped to a label.
+
+ ``help_texts`` is a dictionary of model field names mapped to a help text.
+
+ ``error_messages`` is a dictionary of model field names mapped to a
+ dictionary of error messages.
+
See :ref:`modelforms-factory` for example usage.
.. versionchanged:: 1.6
@@ -35,14 +42,16 @@ Model Form Functions
information. Omitting any definition of the fields to use will result in all
fields being used, but this behavior is deprecated.
- The ``localized_fields`` parameter was added.
+ The ``localized_fields``, ``labels``, ``help_texts``, and
+ ``error_messages`` parameters were added.
-.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None)
+.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None)
Returns a ``FormSet`` class for the given ``model`` class.
Arguments ``model``, ``form``, ``fields``, ``exclude``,
- ``formfield_callback``, ``widgets`` and ``localized_fields`` are all passed through to
+ ``formfield_callback``, ``widgets``, ``localized_fields``, ``labels``,
+ ``help_texts``, and ``error_messages`` are all passed through to
:func:`~django.forms.models.modelform_factory`.
Arguments ``formset``, ``extra``, ``max_num``, ``can_order``,
@@ -54,9 +63,10 @@ Model Form Functions
.. versionchanged:: 1.6
- The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added.
+ The ``widgets``, ``validate_max``, ``localized_fields``, ``labels``,
+ ``help_texts``, and ``error_messages`` parameters were added.
-.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False, localized_fields=None)
+.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None)
Returns an ``InlineFormSet`` using :func:`modelformset_factory` with
defaults of ``formset=BaseInlineFormSet``, ``can_delete=True``, and
@@ -69,4 +79,5 @@ Model Form Functions
.. versionchanged:: 1.6
- The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added.
+ The ``widgets``, ``validate_max`` and ``localized_fields``, ``labels``,
+ ``help_texts``, and ``error_messages`` parameters were added.
diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt
index 87c9764f64..8ab1c26831 100644
--- a/docs/ref/forms/validation.txt
+++ b/docs/ref/forms/validation.txt
@@ -12,13 +12,11 @@ validation (accessing the ``errors`` attribute or calling ``full_clean()``
directly), but normally they won't be needed.
In general, any cleaning method can raise ``ValidationError`` if there is a
-problem with the data it is processing, passing the relevant error message to
-the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the
-method should return the cleaned (normalized) data as a Python object.
-
-If you detect multiple errors during a cleaning method and wish to signal all
-of them to the form submitter, it is possible to pass a list of errors to the
-``ValidationError`` constructor.
+problem with the data it is processing, passing the relevant information to
+the ``ValidationError`` constructor. :ref:`See below <raising-validation-error>`
+for the best practice in raising ``ValidationError``. If no ``ValidationError``
+is raised, the method should return the cleaned (normalized) data as a Python
+object.
Most validation can be done using `validators`_ - simple helpers that can be
reused easily. Validators are simple functions (or callables) that take a single
@@ -87,7 +85,8 @@ overridden:
"field" (called ``__all__``), which you can access via the
``non_field_errors()`` method if you need to. If you want to attach
errors to a specific field in the form, you will need to access the
- ``_errors`` attribute on the form, which is `described later`_.
+ ``_errors`` attribute on the form, which is
+ :ref:`described later <modifying-field-errors>`.
Also note that there are special considerations when overriding
the ``clean()`` method of a ``ModelForm`` subclass. (see the
@@ -116,7 +115,100 @@ should iterate through ``self.cleaned_data.items()``, possibly considering the
``_errors`` dictionary attribute on the form as well. In this way, you will
already know which fields have passed their individual validation requirements.
-.. _described later:
+.. _raising-validation-error:
+
+Raising ``ValidationError``
+---------------------------
+
+.. versionchanged:: 1.6
+
+In order to make error messages flexible and easy to override, consider the
+following guidelines:
+
+* Provide a descriptive error ``code`` to the constructor::
+
+ # Good
+ ValidationError(_('Invalid value'), code='invalid')
+
+ # Bad
+ ValidationError(_('Invalid value'))
+
+* Don't coerce variables into the message; use placeholders and the ``params``
+ argument of the constructor::
+
+ # Good
+ ValidationError(
+ _('Invalid value: %(value)s'),
+ params={'value': '42'},
+ )
+
+ # Bad
+ ValidationError(_('Invalid value: %s') % value)
+
+* Use mapping keys instead of positional formatting. This enables putting
+ the variables in any order or omitting them altogether when rewriting the
+ message::
+
+ # Good
+ ValidationError(
+ _('Invalid value: %(value)s'),
+ params={'value': '42'},
+ )
+
+ # Bad
+ ValidationError(
+ _('Invalid value: %s'),
+ params=('42',),
+ )
+
+* Wrap the message with ``gettext`` to enable translation::
+
+ # Good
+ ValidationError(_('Invalid value'))
+
+ # Bad
+ ValidationError('Invalid value')
+
+Putting it all together::
+
+ raise ValidationErrror(
+ _('Invalid value: %(value)s'),
+ code='invalid',
+ params={'value': '42'},
+ )
+
+Following these guidelines is particularly necessary if you write reusable
+forms, form fields, and model fields.
+
+While not recommended, if you are at the end of the validation chain
+(i.e. your form ``clean()`` method) and you know you will *never* need
+to override your error message you can still opt for the less verbose::
+
+ ValidationError(_('Invalid value: %s') % value)
+
+Raising multiple errors
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If you detect multiple errors during a cleaning method and wish to signal all
+of them to the form submitter, it is possible to pass a list of errors to the
+``ValidationError`` constructor.
+
+As above, it is recommended to pass a list of ``ValidationError`` instances
+with ``code``\s and ``params`` but a list of strings will also work::
+
+ # Good
+ raise ValidationError([
+ ValidationError(_('Error 1'), code='error1'),
+ ValidationError(_('Error 2'), code='error2'),
+ ])
+
+ # Bad
+ raise ValidationError([
+ _('Error 1'),
+ _('Error 2'),
+ ])
+
+.. _modifying-field-errors:
Form subclasses and modifying field errors
------------------------------------------
diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt
index 0f6917d44c..341574ad37 100644
--- a/docs/ref/forms/widgets.txt
+++ b/docs/ref/forms/widgets.txt
@@ -163,6 +163,9 @@ Django will then include the extra attributes in the rendered output:
<tr><th>Url:</th><td><input type="url" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
+You can also set the HTML ``id`` using :attr:`~Widget.attrs`. See
+:attr:`BoundField.id_for_label` for an example.
+
.. _styling-widget-classes:
Styling widget classes
@@ -251,7 +254,7 @@ foundation for custom widgets.
into two separate values::
from django.forms import MultiWidget
-
+
class SplitDateTimeWidget(MultiWidget):
# ...
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index f989ff1bec..cfc95db092 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -84,12 +84,18 @@ need to call a model's :meth:`~Model.full_clean()` method if you plan to handle
validation errors yourself, or if you have excluded fields from the
:class:`~django.forms.ModelForm` that require validation.
-.. method:: Model.full_clean(exclude=None)
+.. method:: Model.full_clean(exclude=None, validate_unique=True)
+
+.. versionchanged:: 1.6
+
+ The ``validate_unique`` parameter was added to allow skipping
+ :meth:`Model.validate_unique()`. Previously, :meth:`Model.validate_unique()`
+ was always called by ``full_clean``.
This method calls :meth:`Model.clean_fields()`, :meth:`Model.clean()`, and
-:meth:`Model.validate_unique()`, in that order and raises a
-:exc:`~django.core.exceptions.ValidationError` that has a ``message_dict``
-attribute containing errors from all three stages.
+:meth:`Model.validate_unique()` (if ``validate_unique`` is ``True``, in that
+order and raises a :exc:`~django.core.exceptions.ValidationError` that has a
+``message_dict`` attribute containing errors from all three stages.
The optional ``exclude`` argument can be used to provide a list of field names
that can be excluded from validation and cleaning.
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index ef52d3170c..897af275a0 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -852,6 +852,10 @@ It is also important to remember that when running with :setting:`DEBUG`
turned on, Django will remember every SQL query it executes. This is useful
when you're debugging, but it'll rapidly consume memory on a production server.
+Finally, if :setting:`DEBUG` is ``False``, you also need to properly set
+the :setting:`ALLOWED_HOSTS` setting. Failing to do so will result in all
+requests being returned as "Bad Request (400)".
+
.. _django/views/debug.py: https://github.com/django/django/blob/master/django/views/debug.py
.. setting:: DEBUG_PROPAGATE_EXCEPTIONS
diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt
index e7270e1957..06ba2cb3e8 100644
--- a/docs/ref/signals.txt
+++ b/docs/ref/signals.txt
@@ -498,17 +498,20 @@ request_finished
Sent when Django finishes processing an HTTP request.
-.. note::
+.. versionchanged:: 1.5
- When a view returns a :ref:`streaming response <httpresponse-streaming>`,
- this signal is sent only after the entire response is consumed by the
- client (strictly speaking, by the WSGI gateway).
+ Before Django 1.5, this signal was sent before delivering content to the
+ client. In order to accommodate :ref:`streaming responses
+ <httpresponse-streaming>`, it is now sent after the response has been fully
+ delivered to the client.
-.. versionchanged:: 1.5
+.. note::
- Before Django 1.5, this signal was fired before sending the content to the
- client. In order to accomodate streaming responses, it is now fired after
- sending the content.
+ Some WSGI servers and middleware do not always call ``close`` on the
+ response object after handling a request, most notably uWSGI prior to 1.2.6
+ and Sentry's error reporting middleware up to 2.0.7. In those cases this
+ signal isn't sent at all. This can result in idle connections to database
+ and memcache servers.
Arguments sent with this signal:
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 24eda2ce2c..afb6e4b123 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -371,7 +371,7 @@ displayed if the given array is empty or could not be found::
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% empty %}
- <li>Sorry, no athlete in this list!</li>
+ <li>Sorry, no athletes in this list.</li>
{% endfor %}
<ul>
@@ -2401,7 +2401,7 @@ It is also able to consume standard context variables, e.g. assuming a
<link rel="stylesheet" href="{% static user_stylesheet %}" type="text/css" media="screen" />
If you'd like to retrieve a static URL without displaying it, you can use a
-slightly different call::
+slightly different call:
.. versionadded:: 1.5
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index d2ef945a2e..45d7781403 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -659,6 +659,8 @@ Functions for working with Python modules.
.. function:: import_by_path(dotted_path, error_prefix='')
+ .. versionadded:: 1.6
+
Imports a dotted module path and returns the attribute/class designated by
the last name in the path. Raises
:exc:`~django.core.exceptions.ImproperlyConfigured` if something goes
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index c54373ee41..a1b046776b 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -440,7 +440,15 @@ generation.
This signal is now sent after the content is fully consumed by the WSGI
gateway. This might be backwards incompatible if you rely on the signal being
fired before sending the response content to the client. If you do, you should
-consider using a middleware instead.
+consider using :doc:`middleware </topics/http/middleware>` instead.
+
+.. note::
+
+ Some WSGI servers and middleware do not always call ``close`` on the
+ response object after handling a request, most notably uWSGI prior to 1.2.6
+ and Sentry's error reporting middleware up to 2.0.7. In those cases the
+ ``request_finished`` signal isn't sent at all. This can result in idle
+ connections to database and memcache servers.
OPTIONS, PUT and DELETE requests in the test client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index 6736af8c2d..bd6255eae6 100644
--- a/docs/releases/1.6.txt
+++ b/docs/releases/1.6.txt
@@ -121,6 +121,13 @@ 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.
+``checksetup`` management command added for verifying compatibility
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``checksetup`` management command was added, enabling you to verify if your
+current configuration (currently oriented at settings) is compatible with the
+current version of Django.
+
Minor features
~~~~~~~~~~~~~~
@@ -236,9 +243,14 @@ Minor features
.. _`Pillow`: https://pypi.python.org/pypi/Pillow
.. _`PIL`: https://pypi.python.org/pypi/PIL
-* :doc:`ModelForm </topics/forms/modelforms/>` accepts a new
- Meta option: ``localized_fields``. Fields included in this list will be localized
- (by setting ``localize`` on the form field).
+* :class:`~django.forms.ModelForm` accepts several new ``Meta``
+ options.
+
+ * Fields included in the ``localized_fields`` list will be localized
+ (by setting ``localize`` on the form field).
+ * The ``labels``, ``help_texts`` and ``error_messages`` options may be used
+ to customize the default fields, see
+ :ref:`modelforms-overriding-default-fields` for details.
* The ``choices`` argument to model fields now accepts an iterable of iterables
instead of requiring an iterable of lists or tuples.
@@ -303,6 +315,21 @@ Minor features
:class:`~django.contrib.admin.InlineModelAdmin` may be overridden to
customize the extra and maximum number of inline forms.
+* Formsets now have a
+ :meth:`~django.forms.formsets.BaseFormSet.total_error_count` method.
+
+* :class:`~django.forms.ModelForm` fields can now override error messages
+ defined in model fields by using the
+ :attr:`~django.forms.Field.error_messages` argument of a ``Field``'s
+ constructor. To take advantage of this new feature with your custom fields,
+ :ref:`see the updated recommendation <raising-validation-error>` for raising
+ a ``ValidationError``.
+
+* :class:`~django.contrib.admin.ModelAdmin` now preserves filters on the list view
+ after creating, editing or deleting an object. It's possible to restore the previous
+ behavior of clearing filters by setting the
+ :attr:`~django.contrib.admin.ModelAdmin.preserve_filters` attribute to ``False``.
+
Backwards incompatible changes in 1.6
=====================================
@@ -581,6 +608,47 @@ It is still possible to convert the fetched rows to ``Model`` objects
lazily by using the :meth:`~django.db.models.query.QuerySet.iterator()`
method.
+:meth:`BoundField.label_tag<django.forms.BoundField.label_tag>` now includes the form's :attr:`~django.forms.Form.label_suffix`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is consistent with how methods like
+:meth:`Form.as_p<django.forms.Form.as_p>` and
+:meth:`Form.as_ul<django.forms.Form.as_ul>` render labels.
+
+If you manually render ``label_tag`` in your templates:
+
+.. code-block:: html+django
+
+ {{ form.my_field.label_tag }}: {{ form.my_field }}
+
+you'll want to remove the semicolon (or whatever other separator you may be
+using) to avoid duplicating it when upgrading to Django 1.6. The following
+template in Django 1.6 will render identically to the above template in Django
+1.5, except that the semicolon will appear inside the ``<label>`` element.
+
+.. code-block:: html+django
+
+ {{ form.my_field.label_tag }} {{ form.my_field }}
+
+will render something like:
+
+.. code-block:: html
+
+ <label for="id_my_field">My Field:</label> <input id="id_my_field" type="text" name="my_field" />
+
+If you want to keep the current behavior of rendering ``label_tag`` without
+the ``label_suffix``, instantiate the form ``label_suffix=''``.
+
+Admin views ``_changelist_filters`` GET parameter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To achieve preserving and restoring list view filters, admin views now
+pass around the `_changelist_filters` GET parameter. It's important that you
+account for that change if you have custom admin templates or if your tests
+rely on the previous URLs. If you want to revert to the original behavior you
+can set the
+:attr:`~django.contrib.admin.ModelAdmin.preserve_filters` attribute to ``False``.
+
Miscellaneous
~~~~~~~~~~~~~
@@ -634,6 +702,29 @@ Miscellaneous
:meth:`django.contrib.auth.logout` which will send the
:func:`~django.contrib.auth.signals.user_logged_out` signal.
+* :ref:`Authentication views <built-in-auth-views>` are now reversed by name,
+ not their locations in ``django.contrib.auth.views``. If you are using the
+ views without a ``name``, you should update your ``urlpatterns`` to use
+ :meth:`~django.conf.urls.url` with the ``name`` parameter. For example::
+
+ (r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete')
+
+ becomes::
+
+ url(r'^reset/done/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete')
+
+* :class:`~django.views.generic.base.RedirectView` now has a `pattern_name`
+ attribute which allows it to choose the target by reversing the URL.
+
+* In Django 1.4 and 1.5, a blank string was unintentionally not considered to
+ be a valid password. This meant
+ :meth:`~django.contrib.auth.models.User.set_password()` would save a blank
+ password as an unusable password like
+ :meth:`~django.contrib.auth.models.User.set_unusable_password()` does, and
+ thus :meth:`~django.contrib.auth.models.User.check_password()` always
+ returned ``False`` for blank passwords. This has been corrected in this
+ release: blank passwords are now valid.
+
Features deprecated in 1.6
==========================
diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt
index bc021b14ad..ee1aedbd8c 100644
--- a/docs/topics/auth/customizing.txt
+++ b/docs/topics/auth/customizing.txt
@@ -37,7 +37,7 @@ plug in other authentication sources. You can override Django's default
database-based scheme, or you can use the default system in tandem with other
systems.
-See the `authentication backend reference
+See the :ref:`authentication backend reference
<authentication-backends-reference>` for information on the authentication
backends included with Django.
@@ -583,12 +583,28 @@ The following methods are available on any subclass of
password hashing. Doesn't save the
:class:`~django.contrib.auth.models.AbstractBaseUser` object.
+ When the raw_password is ``None``, the password will be set to an
+ unusable password, as if
+ :meth:`~django.contrib.auth.models.AbstractBaseUser.set_unusable_password()`
+ were used.
+
+ .. versionchanged:: 1.6
+
+ In Django 1.4 and 1.5, a blank string was unintentionally stored
+ as an unsable password as well.
+
.. method:: models.AbstractBaseUser.check_password(raw_password)
Returns ``True`` if the given raw string is the correct password for
the user. (This takes care of the password hashing in making the
comparison.)
+ .. versionchanged:: 1.6
+
+ In Django 1.4 and 1.5, a blank string was unintentionally
+ considered to be an unusable password, resulting in this method
+ returning ``False`` for such a password.
+
.. method:: models.AbstractBaseUser.set_unusable_password()
Marks the user as having no password set. This isn't the same as
diff --git a/docs/topics/auth/passwords.txt b/docs/topics/auth/passwords.txt
index 206e7d856c..7e4b59a99c 100644
--- a/docs/topics/auth/passwords.txt
+++ b/docs/topics/auth/passwords.txt
@@ -206,6 +206,12 @@ from the ``User`` model.
database to check against, and returns ``True`` if they match, ``False``
otherwise.
+ .. versionchanged:: 1.6
+
+ In Django 1.4 and 1.5, a blank string was unintentionally considered
+ to be an unusable password, resulting in this method returning
+ ``False`` for such a password.
+
.. function:: make_password(password[, salt, hashers])
Creates a hashed password in the format used by this application. It takes
diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt
index 980e571c85..3a4811e7bb 100644
--- a/docs/topics/class-based-views/mixins.txt
+++ b/docs/topics/class-based-views/mixins.txt
@@ -233,7 +233,7 @@ We'll demonstrate this with the publisher modelling we used in the
from django.views.generic.detail import SingleObjectMixin
from books.models import Author
- class RecordInterest(View, SingleObjectMixin):
+ class RecordInterest(SingleObjectMixin, View):
"""Records the current user's interest in an author."""
model = Author
@@ -446,7 +446,7 @@ Our new ``AuthorDetail`` looks like this::
class AuthorInterestForm(forms.Form):
message = forms.CharField()
- class AuthorDetail(DetailView, FormMixin):
+ class AuthorDetail(FormMixin, DetailView):
model = Author
form_class = AuthorInterestForm
@@ -553,7 +553,7 @@ template as ``AuthorDisplay`` is using on ``GET``.
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
- class AuthorInterest(FormView, SingleObjectMixin):
+ class AuthorInterest(SingleObjectMixin, FormView):
template_name = 'books/author_detail.html'
form_class = AuthorInterestForm
model = Author
diff --git a/docs/topics/files.txt b/docs/topics/files.txt
index 492e6a20b5..45f83d8746 100644
--- a/docs/topics/files.txt
+++ b/docs/topics/files.txt
@@ -87,9 +87,9 @@ The following approach may be used to close files automatically::
# Create a Python file object using open() and the with statement
>>> with open('/tmp/hello.world', 'w') as f:
- >>> myfile = File(f)
- >>> for line in myfile:
- >>> print line
+ ... myfile = File(f)
+ ... myfile.write('Hello World')
+ ...
>>> myfile.closed
True
>>> f.closed
diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt
index 8745e9761d..29139c5dea 100644
--- a/docs/topics/forms/formsets.txt
+++ b/docs/topics/forms/formsets.txt
@@ -3,7 +3,7 @@
Formsets
========
-.. class:: django.forms.formset.BaseFormSet
+.. class:: django.forms.formsets.BaseFormSet
A formset is a layer of abstraction to work with multiple forms on the same
page. It can be best compared to a data grid. Let's say you have the following
@@ -164,6 +164,23 @@ As we can see, ``formset.errors`` is a list whose entries correspond to the
forms in the formset. Validation was performed for each of the two forms, and
the expected error message appears for the second item.
+.. currentmodule:: django.forms.formsets.BaseFormSet
+
+.. method:: total_error_count(self)
+
+.. versionadded:: 1.6
+
+To check how many errors there are in the formset, we can use the
+``total_error_count`` method::
+
+ >>> # Using the previous example
+ >>> formset.errors
+ [{}, {'pub_date': [u'This field is required.']}]
+ >>> len(formset.errors)
+ 2
+ >>> formset.total_error_count()
+ 1
+
We can also check if form data differs from the initial data (i.e. the form was
sent without any data)::
@@ -247,8 +264,7 @@ is where you define your own validation that works at the formset level::
... # Don't bother validating the formset unless each form is valid on its own
... return
... titles = []
- ... for i in range(0, self.total_form_count()):
- ... form = self.forms[i]
+ ... for form in self.forms:
... title = form.cleaned_data['title']
... if title in titles:
... raise forms.ValidationError("Articles in a set must have distinct titles.")
diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt
index ac58acc9e3..7d5a0ed411 100644
--- a/docs/topics/forms/index.txt
+++ b/docs/topics/forms/index.txt
@@ -302,7 +302,7 @@ loop::
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
- {{ field.label_tag }}: {{ field }}
+ {{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
@@ -316,8 +316,14 @@ attributes, which can be useful in your templates:
The label of the field, e.g. ``Email address``.
``{{ field.label_tag }}``
- The field's label wrapped in the appropriate HTML ``<label>`` tag,
- e.g. ``<label for="id_email">Email address</label>``
+ The field's label wrapped in the appropriate HTML ``<label>`` tag.
+
+ .. versionchanged:: 1.6
+
+ This includes the form's :attr:`~django.forms.Form.label_suffix`. For
+ example, the default ``label_suffix`` is a semicolon::
+
+ <label for="id_email">Email address:</label>
``{{ field.value }}``
The value of the field. e.g ``someone@example.com``
@@ -375,7 +381,7 @@ these two methods::
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
- {{ field.label_tag }}: {{ field }}
+ {{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
@@ -403,7 +409,7 @@ using the :ttag:`include` tag to reuse it in other templates::
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
- {{ field.label_tag }}: {{ field }}
+ {{ field.label_tag }} {{ field }}
</div>
{% endfor %}
diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt
index b014e97119..a1fd533241 100644
--- a/docs/topics/forms/media.txt
+++ b/docs/topics/forms/media.txt
@@ -49,7 +49,7 @@ define the media requirements.
Here's a simple example::
- from django import froms
+ from django import forms
class CalendarWidget(forms.TextInput):
class Media:
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index 4c46c6c0c0..bd9e14aea4 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -141,7 +141,7 @@ In addition, each generated form field has attributes set as follows:
``default`` value will be initially selected instead).
Finally, note that you can override the form field used for a given model
-field. See `Overriding the default field types or widgets`_ below.
+field. See `Overriding the default fields`_ below.
A full example
--------------
@@ -388,8 +388,10 @@ include that field.
.. _section on saving forms: `The save() method`_
-Overriding the default field types or widgets
----------------------------------------------
+.. _modelforms-overriding-default-fields:
+
+Overriding the default fields
+-----------------------------
The default field types, as described in the `Field types`_ table above, are
sensible defaults. If you have a ``DateField`` in your model, chances are you'd
@@ -420,38 +422,65 @@ widget::
The ``widgets`` dictionary accepts either widget instances (e.g.,
``Textarea(...)``) or classes (e.g., ``Textarea``).
-If you want to further customize a field -- including its type, label, etc. --
-you can do this by declaratively specifying fields like you would in a regular
-``Form``. Declared fields will override the default ones generated by using the
-``model`` attribute.
+.. versionadded:: 1.6
+
+ The ``labels``, ``help_texts`` and ``error_messages`` options were added.
+
+Similarly, you can specify the ``labels``, ``help_texts`` and ``error_messages``
+attributes of the inner ``Meta`` class if you want to further customize a field.
-For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
+For example if you wanted to customize the wording of all user facing strings for
+the ``name`` field::
+
+ class AuthorForm(ModelForm):
+ class Meta:
+ model = Author
+ fields = ('name', 'title', 'birth_date')
+ labels = {
+ 'name': _('Writer'),
+ }
+ help_texts = {
+ 'name': _('Some useful help text.'),
+ }
+ error_messages = {
+ 'name': {
+ 'max_length': _("This writer's name is too long."),
+ },
+ }
+
+Finally, if you want complete control over of a field -- including its type,
+validators, etc. -- you can do this by declaratively specifying fields like you
+would in a regular ``Form``. Declared fields will override the default ones
+generated by using the ``model`` attribute. Fields declared like this will
+ignore any customizations in the ``widgets``, ``labels``, ``help_texts``, and
+``error_messages`` options declared on ``Meta``.
+
+For example, if you wanted to use ``MySlugFormField`` for the ``slug``
field, you could do the following::
from django.forms import ModelForm
from myapp.models import Article
class ArticleForm(ModelForm):
- pub_date = MyDateFormField()
+ slug = MySlugFormField()
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
-If you want to override a field's default label, then specify the ``label``
-parameter when declaring the form field::
+If you want to override a field's default validators, then specify the
+``validators`` parameter when declaring the form field::
from django.forms import ModelForm, DateField
from myapp.models import Article
class ArticleForm(ModelForm):
- pub_date = DateField(label='Publication date')
+ slug = CharField(validators=[validate_slug])
class Meta:
model = Article
- fields = ['pub_date', 'headline', 'content', 'reporter']
-
+ fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
.. note::
@@ -597,7 +626,7 @@ example by specifying the widgets to be used for a given field::
>>> from django.forms import Textarea
>>> Form = modelform_factory(Book, form=BookForm,
- widgets={"title": Textarea()})
+ ... widgets={"title": Textarea()})
The fields to include can be specified using the ``fields`` and ``exclude``
keyword arguments, or the corresponding attributes on the ``ModelForm`` inner
@@ -907,7 +936,7 @@ Third, you can manually render each field::
{{ formset.management_form }}
{% for form in formset %}
{% for field in form %}
- {{ field.label_tag }}: {{ field }}
+ {{ field.label_tag }} {{ field }}
{% endfor %}
{% endfor %}
</form>
diff --git a/docs/topics/settings.txt b/docs/topics/settings.txt
index fa26297988..1cfcd262cd 100644
--- a/docs/topics/settings.txt
+++ b/docs/topics/settings.txt
@@ -17,6 +17,11 @@ Here are a couple of example settings::
DEFAULT_FROM_EMAIL = 'webmaster@example.com'
TEMPLATE_DIRS = ('/home/templates/mike', '/home/templates/john')
+.. note::
+
+ If you set :setting:`DEBUG` to ``False``, you also need to properly set
+ the :setting:`ALLOWED_HOSTS` setting.
+
Because a settings file is a Python module, the following apply:
* It doesn't allow for Python syntax errors.
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index b7f49d2b97..8f7f093901 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -155,6 +155,80 @@ If there are any circular dependencies in the
:setting:`TEST_DEPENDENCIES` definition, an ``ImproperlyConfigured``
exception will be raised.
+Advanced features of ``TransactionTestCase``
+============================================
+
+.. currentmodule:: django.test
+
+.. attribute:: TransactionTestCase.available_apps
+
+ .. versionadded:: 1.6
+
+ .. warning::
+
+ This attribute is a private API. It may be changed or removed without
+ a deprecation period in the future, for instance to accomodate changes
+ in application loading.
+
+ It's used to optimize Django's own test suite, which contains hundreds
+ of models but no relations between models in different applications.
+
+ By default, ``available_apps`` is set to ``None``. After each test, Django
+ calls :djadmin:`flush` to reset the database state. This empties all tables
+ and emits the :data:`~django.db.models.signals.post_syncdb` signal, which
+ re-creates one content type and three permissions for each model. This
+ operation gets expensive proportionally to the number of models.
+
+ Setting ``available_apps`` to a list of applications instructs Django to
+ behave as if only the models from these applications were available. The
+ behavior of ``TransactionTestCase`` changes as follows:
+
+ - :data:`~django.db.models.signals.post_syncdb` is fired before each
+ test to create the content types and permissions for each model in
+ available apps, in case they're missing.
+ - After each test, Django empties only tables corresponding to models in
+ available apps. However, at the database level, truncation may cascade to
+ related models in unavailable apps. Furthermore
+ :data:`~django.db.models.signals.post_syncdb` isn't fired; it will be
+ fired by the next ``TransactionTestCase``, after the correct set of
+ applications is selected.
+
+ Since the database isn't fully flushed, if a test creates instances of
+ models not included in ``available_apps``, they will leak and they may
+ cause unrelated tests to fail. Be careful with tests that use sessions;
+ the default session engine stores them in the database.
+
+ Since :data:`~django.db.models.signals.post_syncdb` isn't emitted after
+ flushing the database, its state after a ``TransactionTestCase`` isn't the
+ same as after a ``TestCase``: it's missing the rows created by listeners
+ to :data:`~django.db.models.signals.post_syncdb`. Considering the
+ :ref:`order in which tests are executed <order-of-tests>`, this isn't an
+ issue, provided either all ``TransactionTestCase`` in a given test suite
+ declare ``available_apps``, or none of them.
+
+ ``available_apps`` is mandatory in Django's own test suite.
+
+.. attribute:: TransactionTestCase.reset_sequences
+
+ .. versionadded:: 1.5
+
+ Setting ``reset_sequences = True`` on a ``TransactionTestCase`` will make
+ sure sequences are always reset before the test run::
+
+ class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
+ reset_sequences = True
+
+ def test_animal_pk(self):
+ lion = Animal.objects.create(name="lion", sound="roar")
+ # lion.pk is guaranteed to always be 1
+ self.assertEqual(lion.pk, 1)
+
+ Unless you are explicitly testing primary keys sequence numbers, it is
+ recommended that you do not hard code primary key values in tests.
+
+ Using ``reset_sequences = True`` will slow down the test, since the primary
+ key reset is an relatively expensive database operation.
+
Running tests outside the test runner
=====================================
diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt
index 2b1db5e501..8268051a36 100644
--- a/docs/topics/testing/overview.txt
+++ b/docs/topics/testing/overview.txt
@@ -213,6 +213,8 @@ advanced settings.
The :ref:`advanced multi-db testing topics <topics-testing-advanced-multidb>`.
+.. _order-of-tests:
+
Order in which tests are executed
---------------------------------
@@ -908,8 +910,8 @@ TransactionTestCase
.. class:: TransactionTestCase()
-Django ``TestCase`` classes make use of database transaction facilities, if
-available, to speed up the process of resetting the database to a known state
+Django's ``TestCase`` class (described below) makes use of database transaction
+facilities to speed up the process of resetting the database to a known state
at the beginning of each test. A consequence of this, however, is that the
effects of transaction commit and rollback cannot be tested by a Django
``TestCase`` class. If your test requires testing of such transactional
@@ -927,9 +929,9 @@ to test the effects of commit and rollback:
Instead, it encloses the test code in a database transaction that is rolled
back at the end of the test. Both explicit commits like
``transaction.commit()`` and implicit ones that may be caused by
- ``Model.save()`` are replaced with a ``nop`` operation. This guarantees that
- the rollback at the end of the test restores the database to its initial
- state.
+ ``transaction.atomic()`` are replaced with a ``nop`` operation. This
+ guarantees that the rollback at the end of the test restores the database to
+ its initial state.
When running on a database that does not support rollback (e.g. MySQL with the
MyISAM storage engine), ``TestCase`` falls back to initializing the database
@@ -940,22 +942,21 @@ to test the effects of commit and rollback:
While ``commit`` and ``rollback`` operations still *appear* to work when
used in ``TestCase``, no actual commit or rollback will be performed by the
database. This can cause your tests to pass or fail unexpectedly. Always
- use ``TransactionalTestCase`` when testing transactional behavior.
-
-.. note::
+ use ``TransactionTestCase`` when testing transactional behavior.
- .. versionchanged:: 1.5
+.. versionchanged:: 1.5
- Prior to 1.5, ``TransactionTestCase`` flushed the database tables *before*
- each test. In Django 1.5, this is instead done *after* the test has been run.
+ Prior to 1.5, :class:`~django.test.TransactionTestCase` flushed the
+ database tables *before* each test. In Django 1.5, this is instead done
+ *after* the test has been run.
When the flush took place before the test, it was guaranteed that primary
key values started at one in :class:`~django.test.TransactionTestCase`
tests.
- Tests should not depend on this behavior, but for legacy tests that do, the
- :attr:`~TransactionTestCase.reset_sequences` attribute can be used until
- the test has been properly updated.
+ Tests should not depend on this behavior, but for legacy tests that do,
+ the :attr:`~TransactionTestCase.reset_sequences` attribute can be used
+ until the test has been properly updated.
.. versionchanged:: 1.5
@@ -964,27 +965,6 @@ to test the effects of commit and rollback:
``TransactionTestCase`` inherits from :class:`~django.test.SimpleTestCase`.
-.. attribute:: TransactionTestCase.reset_sequences
-
- .. versionadded:: 1.5
-
- Setting ``reset_sequences = True`` on a ``TransactionTestCase`` will make
- sure sequences are always reset before the test run::
-
- class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
- reset_sequences = True
-
- def test_animal_pk(self):
- lion = Animal.objects.create(name="lion", sound="roar")
- # lion.pk is guaranteed to always be 1
- self.assertEqual(lion.pk, 1)
-
- Unless you are explicitly testing primary keys sequence numbers, it is
- recommended that you do not hard code primary key values in tests.
-
- Using ``reset_sequences = True`` will slow down the test, since the primary
- key reset is an relatively expensive database operation.
-
TestCase
~~~~~~~~
@@ -1467,7 +1447,7 @@ Emptying the test outbox
~~~~~~~~~~~~~~~~~~~~~~~~
If you use any of Django's custom ``TestCase`` classes, the test runner will
-clear thecontents of the test email outbox at the start of each test case.
+clear the contents of the test email outbox at the start of each test case.
For more detail on email services during tests, see `Email services`_ below.