1230 lines
54 KiB
Plaintext
1230 lines
54 KiB
Plaintext
=========================
|
||
Django 1.6 release notes
|
||
=========================
|
||
|
||
.. note::
|
||
|
||
Dedicated to Malcolm Tredinnick
|
||
|
||
On March 17, 2013, the Django project and the free software community lost
|
||
a very dear friend and developer.
|
||
|
||
Malcolm was a long-time contributor to Django, a model community member, a
|
||
brilliant mind, and a friend. His contributions to Django — and to many other
|
||
open source projects — are nearly impossible to enumerate. Many on the core
|
||
Django team had their first patches reviewed by him; his mentorship enriched
|
||
us. His consideration, patience, and dedication will always be an inspiration
|
||
to us.
|
||
|
||
This release of Django is for Malcolm.
|
||
|
||
-- The Django Developers
|
||
|
||
*November 6, 2013*
|
||
|
||
Welcome to Django 1.6!
|
||
|
||
These release notes cover the `new features`_, as well as some `backwards
|
||
incompatible changes`_ you'll want to be aware of when upgrading from Django
|
||
1.5 or older versions. We've also dropped some features, which are detailed in
|
||
:ref:`our deprecation plan <deprecation-removed-in-1.6>`, and we've `begun the
|
||
deprecation process for some features`_.
|
||
|
||
.. _`new features`: `What's new in Django 1.6`_
|
||
.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.6`_
|
||
.. _`begun the deprecation process for some features`: `Features deprecated in 1.6`_
|
||
|
||
Python compatibility
|
||
====================
|
||
|
||
Django 1.6, like Django 1.5, requires Python 2.6.5 or above. Python 3 is also
|
||
officially supported. We **highly recommend** the latest minor release for each
|
||
supported Python series (2.6.X, 2.7.X, 3.2.X, and 3.3.X).
|
||
|
||
Django 1.6 will be the final release series to support Python 2.6; beginning
|
||
with Django 1.7, the minimum supported Python version will be 2.7.
|
||
|
||
Python 3.4 is not supported, but support will be added in Django 1.7.
|
||
|
||
What's new in Django 1.6
|
||
========================
|
||
|
||
Simplified default project and app templates
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The default templates used by :djadmin:`startproject` and :djadmin:`startapp`
|
||
have been simplified and modernized. The :doc:`admin
|
||
</ref/contrib/admin/index>` is now enabled by default in new projects; the
|
||
:doc:`sites </ref/contrib/sites>` framework no longer is. :ref:`clickjacking
|
||
prevention <clickjacking-prevention>` is now on and the database defaults to
|
||
SQLite.
|
||
|
||
If the default templates don't suit your tastes, you can use :ref:`custom
|
||
project and app templates <custom-app-and-project-templates>`.
|
||
|
||
Improved transaction management
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django's transaction management was overhauled. Database-level autocommit is
|
||
now turned on by default. This makes transaction handling more explicit and
|
||
should improve performance. The existing APIs were deprecated, and new APIs
|
||
were introduced, as described in the :doc:`transaction management docs
|
||
</topics/db/transactions>`.
|
||
|
||
Please review carefully the list of :ref:`known backwards-incompatibilities
|
||
<transactions-upgrading-from-1.5>` to determine if you need to make changes in
|
||
your code.
|
||
|
||
Persistent database connections
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django now supports reusing the same database connection for several requests.
|
||
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.DiscoverRunner``) 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
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The support for :doc:`time zones </topics/i18n/timezones>` introduced in
|
||
Django 1.4 didn't work well with :meth:`QuerySet.dates()
|
||
<django.db.models.query.QuerySet.dates>`: aggregation was always performed in
|
||
UTC. This limitation was lifted in Django 1.6. Use :meth:`QuerySet.datetimes()
|
||
<django.db.models.query.QuerySet.datetimes>` to perform time zone aware
|
||
aggregation on a :class:`~django.db.models.DateTimeField`.
|
||
|
||
Support for savepoints in SQLite
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django 1.6 adds support for savepoints in SQLite, with some :ref:`limitations
|
||
<savepoints-in-sqlite>`.
|
||
|
||
``BinaryField`` model field
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
A new :class:`django.db.models.BinaryField` model field allows storage of raw
|
||
binary data in the database.
|
||
|
||
GeoDjango form widgets
|
||
~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
GeoDjango now provides :doc:`form fields and widgets </ref/contrib/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.
|
||
|
||
``check`` management command added for verifying compatibility
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
A :djadmin:`check` management command was added, enabling you to verify if your
|
||
current configuration (currently oriented at settings) is compatible with the
|
||
current version of Django.
|
||
|
||
:meth:`Model.save() <django.db.models.Model.save()>` algorithm changed
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The :meth:`Model.save() <django.db.models.Model.save()>` method now
|
||
tries to directly ``UPDATE`` the database if the instance has a primary
|
||
key value. Previously ``SELECT`` was performed to determine if ``UPDATE``
|
||
or ``INSERT`` were needed. The new algorithm needs only one query for
|
||
updating an existing row while the old algorithm needed two. See
|
||
:meth:`Model.save() <django.db.models.Model.save()>` for more details.
|
||
|
||
In some rare cases the database doesn't report that a matching row was
|
||
found when doing an ``UPDATE``. An example is the PostgreSQL ``ON UPDATE``
|
||
trigger which returns ``NULL``. In such cases it is possible to set
|
||
:attr:`django.db.models.Options.select_on_save` flag to force saving to
|
||
use the old algorithm.
|
||
|
||
Minor features
|
||
~~~~~~~~~~~~~~
|
||
|
||
* Authentication backends can raise ``PermissionDenied`` to immediately fail
|
||
the authentication chain.
|
||
|
||
* The ``HttpOnly`` flag can be set on the CSRF cookie with
|
||
:setting:`CSRF_COOKIE_HTTPONLY`.
|
||
|
||
* The :meth:`~django.test.TransactionTestCase.assertQuerysetEqual` now checks
|
||
for undefined order and raises :exc:`ValueError` if undefined
|
||
order is spotted. The order is seen as undefined if the given ``QuerySet``
|
||
isn't ordered and there are more than one ordered values to compare against.
|
||
|
||
* Added :meth:`~django.db.models.query.QuerySet.earliest` for symmetry with
|
||
:meth:`~django.db.models.query.QuerySet.latest`.
|
||
|
||
* In addition to :lookup:`year`, :lookup:`month` and :lookup:`day`, the ORM
|
||
now supports :lookup:`hour`, :lookup:`minute` and :lookup:`second` lookups.
|
||
|
||
* Django now wraps all PEP-249 exceptions.
|
||
|
||
* The default widgets for :class:`~django.forms.EmailField`,
|
||
:class:`~django.forms.URLField`, :class:`~django.forms.IntegerField`,
|
||
:class:`~django.forms.FloatField` and :class:`~django.forms.DecimalField` use
|
||
the new type attributes available in HTML5 (``type='email'``, ``type='url'``,
|
||
``type='number'``). Note that due to erratic support of the ``number``
|
||
input type with localized numbers in current browsers, Django only uses it
|
||
when numeric fields are not localized.
|
||
|
||
* The ``number`` argument for :ref:`lazy plural translations
|
||
<lazy-plural-translations>` can be provided at translation time rather than
|
||
at definition time.
|
||
|
||
* For custom management commands: Verification of the presence of valid
|
||
settings in commands that ask for it by using the
|
||
:attr:`~django.core.management.BaseCommand.can_import_settings` internal
|
||
option is now performed independently from handling of the locale that
|
||
should be active during the execution of the command. The latter can now be
|
||
influenced by the new
|
||
:attr:`~django.core.management.BaseCommand.leave_locale_alone` internal
|
||
option. See :ref:`management-commands-and-locales` for more details.
|
||
|
||
* The :attr:`~django.views.generic.edit.DeletionMixin.success_url` of
|
||
:class:`~django.views.generic.edit.DeletionMixin` is now interpolated with
|
||
its ``object``’s ``__dict__``.
|
||
|
||
* :class:`~django.http.HttpResponseRedirect` and
|
||
:class:`~django.http.HttpResponsePermanentRedirect` now provide an ``url``
|
||
attribute (equivalent to the URL the response will redirect to).
|
||
|
||
* The ``MemcachedCache`` cache backend now uses the latest :mod:`pickle`
|
||
protocol available.
|
||
|
||
* Added :class:`~django.contrib.messages.views.SuccessMessageMixin` which
|
||
provides a ``success_message`` attribute for
|
||
:class:`~django.views.generic.edit.FormView` based classes.
|
||
|
||
* Added the :attr:`django.db.models.ForeignKey.db_constraint` and
|
||
:attr:`django.db.models.ManyToManyField.db_constraint` options.
|
||
|
||
* The jQuery library embedded in the admin has been upgraded to version 1.9.1.
|
||
|
||
* Syndication feeds (:mod:`django.contrib.syndication`) can now pass extra
|
||
context through to feed templates using a new
|
||
:meth:`Feed.get_context_data()
|
||
<django.contrib.syndication.Feed.get_context_data>` callback.
|
||
|
||
* The admin list columns have a ``column-<field_name>`` class in the HTML
|
||
so the columns header can be styled with CSS, e.g. to set a column width.
|
||
|
||
* The :ref:`isolation level<database-isolation-level>` can be customized under
|
||
PostgreSQL.
|
||
|
||
* The :ttag:`blocktrans` template tag now respects
|
||
``TEMPLATE_STRING_IF_INVALID`` for variables not present in the
|
||
context, just like other template constructs.
|
||
|
||
* ``SimpleLazyObject``\s will now present more helpful representations in shell
|
||
debugging situations.
|
||
|
||
* Generic :class:`~django.contrib.gis.db.models.GeometryField` is now editable
|
||
with the OpenLayers widget in the admin.
|
||
|
||
* The documentation contains a :doc:`deployment checklist
|
||
</howto/deployment/checklist>`.
|
||
|
||
* The :djadmin:`diffsettings` command gained a ``--all`` option.
|
||
|
||
* ``django.forms.fields.Field.__init__`` now calls ``super()``, allowing
|
||
field mixins to implement ``__init__()`` methods that will reliably be
|
||
called.
|
||
|
||
* The ``validate_max`` parameter was added to ``BaseFormSet`` and
|
||
:func:`~django.forms.formsets.formset_factory`, and ``ModelForm`` and inline
|
||
versions of the same. The behavior of validation for formsets with
|
||
``max_num`` was clarified. The previously undocumented behavior that
|
||
hardened formsets against memory exhaustion attacks was documented,
|
||
and the undocumented limit of the higher of 1000 or ``max_num`` forms
|
||
was changed so it is always 1000 more than ``max_num``.
|
||
|
||
* 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
|
||
|
||
* :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.
|
||
|
||
* The reason phrase can be customized in HTTP responses using
|
||
:attr:`~django.http.HttpResponse.reason_phrase`.
|
||
|
||
* When giving the URL of the next page for
|
||
:func:`~django.contrib.auth.views.logout`,
|
||
:func:`~django.contrib.auth.views.password_reset`,
|
||
:func:`~django.contrib.auth.views.password_reset_confirm`,
|
||
and :func:`~django.contrib.auth.views.password_change`, you can now pass
|
||
URL names and they will be resolved.
|
||
|
||
* The :djadmin:`dumpdata` ``manage.py`` command now has a :djadminopt:`--pks`
|
||
option which will allow users to specify the primary keys of objects they
|
||
want to dump. This option can only be used with one model.
|
||
|
||
* Added ``QuerySet`` methods :meth:`~django.db.models.query.QuerySet.first`
|
||
and :meth:`~django.db.models.query.QuerySet.last` which are convenience
|
||
methods returning the first or last object matching the filters. Returns
|
||
``None`` if there are no objects matching.
|
||
|
||
* :class:`~django.views.generic.base.View` and
|
||
:class:`~django.views.generic.base.RedirectView` now support HTTP ``PATCH``
|
||
method.
|
||
|
||
* ``GenericForeignKey`` now takes an optional ``for_concrete_model`` argument,
|
||
which when set to ``False`` allows the field to reference proxy models. The
|
||
default is ``True`` to retain the old behavior.
|
||
|
||
* The :class:`~django.middleware.locale.LocaleMiddleware` now stores the active
|
||
language in session if it is not present there. This prevents loss of
|
||
language settings after session flush, e.g. logout.
|
||
|
||
* :exc:`~django.core.exceptions.SuspiciousOperation` has been differentiated
|
||
into a number of subclasses, and each will log to a matching named logger
|
||
under the ``django.security`` logging hierarchy. Along with this change,
|
||
a ``handler400`` mechanism and default view are used whenever
|
||
a ``SuspiciousOperation`` reaches the WSGI handler to return an
|
||
``HttpResponseBadRequest``.
|
||
|
||
* The :exc:`~django.core.exceptions.DoesNotExist` exception now includes a
|
||
message indicating the name of the attribute used for the lookup.
|
||
|
||
* The :meth:`~django.db.models.query.QuerySet.get_or_create` method no longer
|
||
requires at least one keyword argument.
|
||
|
||
* The :class:`~django.test.SimpleTestCase` class includes a new assertion
|
||
helper for testing formset errors:
|
||
:meth:`~django.test.SimpleTestCase.assertFormsetError`.
|
||
|
||
* The list of related fields added to a
|
||
:class:`~django.db.models.query.QuerySet` by
|
||
:meth:`~django.db.models.query.QuerySet.select_related` can be cleared using
|
||
``select_related(None)``.
|
||
|
||
* The :meth:`~django.contrib.admin.InlineModelAdmin.get_extra` and
|
||
:meth:`~django.contrib.admin.InlineModelAdmin.get_max_num` methods on
|
||
: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``.
|
||
|
||
* Added
|
||
:meth:`FormMixin.get_prefix<django.views.generic.edit.FormMixin.get_prefix>`
|
||
(which returns
|
||
:attr:`FormMixin.prefix<django.views.generic.edit.FormMixin.prefix>` by
|
||
default) to allow customizing the :attr:`~django.forms.Form.prefix` of the
|
||
form.
|
||
|
||
* Raw queries (``Manager.raw()`` or ``cursor.execute()``) can now use the
|
||
"pyformat" parameter style, where placeholders in the query are given as
|
||
``'%(name)s'`` and the parameters are passed as a dictionary rather than
|
||
a list (except on SQLite). This has long been possible (but not officially
|
||
supported) on MySQL and PostgreSQL, and is now also available on Oracle.
|
||
|
||
* The default iteration count for the PBKDF2 password hasher has been
|
||
increased by 20%. This backwards compatible change will not affect
|
||
existing passwords or users who have subclassed
|
||
``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
|
||
default value. Passwords :ref:`will be upgraded <password-upgrades>` to use
|
||
the new iteration count as necessary.
|
||
|
||
Backwards incompatible changes in 1.6
|
||
=====================================
|
||
|
||
.. warning::
|
||
|
||
In addition to the changes outlined in this section, be sure to review the
|
||
:ref:`deprecation plan <deprecation-removed-in-1.6>` for any features that
|
||
have been removed. If you haven't updated your code within the
|
||
deprecation timeline for a given feature, its removal may appear as a
|
||
backwards incompatible change.
|
||
|
||
New transaction management model
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Behavior changes
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
Database-level autocommit is enabled by default in Django 1.6. While this
|
||
doesn't change the general spirit of Django's transaction management, there
|
||
are a few known backwards-incompatibilities, described in the :ref:`transaction
|
||
management docs <transactions-upgrading-from-1.5>`. You should review your
|
||
code to determine if you're affected.
|
||
|
||
Savepoints and ``assertNumQueries``
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
The changes in transaction management may result in additional statements to
|
||
create, release or rollback savepoints. This is more likely to happen with
|
||
SQLite, since it didn't support savepoints until this release.
|
||
|
||
If tests using :meth:`~django.test.TransactionTestCase.assertNumQueries` fail
|
||
because of a higher number of queries than expected, check that the extra
|
||
queries are related to savepoints, and adjust the expected number of queries
|
||
accordingly.
|
||
|
||
Autocommit option for PostgreSQL
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
In previous versions, database-level autocommit was only an option for
|
||
PostgreSQL, and it was disabled by default. This option is now ignored 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``) and includes some additional
|
||
doctest utilities. 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: https://docs.python.org/library/doctest.html#unittest-api
|
||
|
||
Removal of ``django.contrib.gis.tests.GeoDjangoTestSuiteRunner`` GeoDjango custom test runner
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
This is for developers working on the GeoDjango application itself and related
|
||
to the item above about changes in the test runners:
|
||
|
||
The ``django.contrib.gis.tests.GeoDjangoTestSuiteRunner`` test runner has been
|
||
removed and the standalone GeoDjango tests execution setup it implemented isn't
|
||
supported anymore. To run the GeoDjango tests simply use the new
|
||
``DiscoverRunner`` and specify the ``django.contrib.gis`` app.
|
||
|
||
Custom User models in tests
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The introduction of the new test runner has also slightly changed the way that
|
||
test models are imported. As a result, any test that overrides ``AUTH_USER_MODEL``
|
||
to test behavior with one of Django's test user models (
|
||
:class:`~django.contrib.auth.tests.custom_user.CustomUser` and
|
||
:class:`~django.contrib.auth.tests.custom_user.ExtensionUser`) must now
|
||
explicitly import the User model in your test module::
|
||
|
||
from django.contrib.auth.tests.custom_user import CustomUser
|
||
|
||
@override_settings(AUTH_USER_MODEL='auth.CustomUser')
|
||
class CustomUserFeatureTests(TestCase):
|
||
def test_something(self):
|
||
# Test code here ...
|
||
|
||
This import forces the custom user model to be registered. Without this import,
|
||
the test will be unable to swap in the custom user model, and you will get an
|
||
error reporting::
|
||
|
||
ImproperlyConfigured: AUTH_USER_MODEL refers to model 'auth.CustomUser' that has not been installed
|
||
|
||
Time zone-aware ``day``, ``month``, and ``week_day`` lookups
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django 1.6 introduces time zone support for :lookup:`day`, :lookup:`month`,
|
||
and :lookup:`week_day` lookups when :setting:`USE_TZ` is ``True``. These
|
||
lookups were previously performed in UTC regardless of the current time zone.
|
||
|
||
This requires :ref:`time zone definitions in the database
|
||
<database-time-zone-definitions>`. If you're using SQLite, you must install
|
||
pytz_. If you're using MySQL, you must install pytz_ and load the time zone
|
||
tables with `mysql_tzinfo_to_sql`_.
|
||
|
||
.. _pytz: http://pytz.sourceforge.net/
|
||
.. _mysql_tzinfo_to_sql: http://dev.mysql.com/doc/refman/5.6/en/mysql-tzinfo-to-sql.html
|
||
|
||
Addition of ``QuerySet.datetimes()``
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
When the :doc:`time zone support </topics/i18n/timezones>` added in Django 1.4
|
||
was active, :meth:`QuerySet.dates() <django.db.models.query.QuerySet.dates>`
|
||
lookups returned unexpected results, because the aggregation was performed in
|
||
UTC. To fix this, Django 1.6 introduces a new API, :meth:`QuerySet.datetimes()
|
||
<django.db.models.query.QuerySet.datetimes>`. This requires a few changes in
|
||
your code.
|
||
|
||
``QuerySet.dates()`` returns ``date`` objects
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
:meth:`QuerySet.dates() <django.db.models.query.QuerySet.dates>` now returns a
|
||
list of :class:`~datetime.date`. It used to return a list of
|
||
:class:`~datetime.datetime`.
|
||
|
||
:meth:`QuerySet.datetimes() <django.db.models.query.QuerySet.datetimes>`
|
||
returns a list of :class:`~datetime.datetime`.
|
||
|
||
``QuerySet.dates()`` no longer usable on ``DateTimeField``
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
:meth:`QuerySet.dates() <django.db.models.query.QuerySet.dates>` raises an
|
||
error if it's used on :class:`~django.db.models.DateTimeField` when time
|
||
zone support is active. Use :meth:`QuerySet.datetimes()
|
||
<django.db.models.query.QuerySet.datetimes>` instead.
|
||
|
||
``date_hierarchy`` requires time zone definitions
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
The :attr:`~django.contrib.admin.ModelAdmin.date_hierarchy` feature of the
|
||
admin now relies on :meth:`QuerySet.datetimes()
|
||
<django.db.models.query.QuerySet.datetimes>` when it's used on a
|
||
:class:`~django.db.models.DateTimeField`.
|
||
|
||
This requires time zone definitions in the database when :setting:`USE_TZ` is
|
||
``True``. :ref:`Learn more <database-time-zone-definitions>`.
|
||
|
||
``date_list`` in generic views requires time zone definitions
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
For the same reason, accessing ``date_list`` in the context of a date-based
|
||
generic view requires time zone definitions in the database when the view is
|
||
based on a :class:`~django.db.models.DateTimeField` and :setting:`USE_TZ` is
|
||
``True``. :ref:`Learn more <database-time-zone-definitions>`.
|
||
|
||
New lookups may clash with model fields
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django 1.6 introduces ``hour``, ``minute``, and ``second`` lookups on
|
||
:class:`~django.db.models.DateTimeField`. If you had model fields called
|
||
``hour``, ``minute``, or ``second``, the new lookups will clash with you field
|
||
names. Append an explicit :lookup:`exact` lookup if this is an issue.
|
||
|
||
``BooleanField`` no longer defaults to ``False``
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
When a :class:`~django.db.models.BooleanField` doesn't have an explicit
|
||
:attr:`~django.db.models.Field.default`, the implicit default value is
|
||
``None``. In previous version of Django, it was ``False``, but that didn't
|
||
represent accurately the lack of a value.
|
||
|
||
Code that relies on the default value being ``False`` may raise an exception
|
||
when saving new model instances to the database, because ``None`` isn't an
|
||
acceptable value for a :class:`~django.db.models.BooleanField`. You should
|
||
either specify ``default=False`` in the field definition, or ensure the field
|
||
is set to ``True`` or ``False`` before saving the object.
|
||
|
||
Translations and comments in templates
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Extraction of translations after comments
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
Extraction of translatable literals from templates with the
|
||
:djadmin:`makemessages` command now correctly detects i18n constructs when
|
||
they are located after a ``{#`` / ``#}``-type comment on the same line. E.g.:
|
||
|
||
.. code-block:: html+django
|
||
|
||
{# A comment #}{% trans "This literal was incorrectly ignored. Not anymore" %}
|
||
|
||
Location of translator comments
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
:ref:`translator-comments-in-templates` specified using ``{#`` / ``#}`` need to
|
||
be at the end of a line. If they are not, the comments are ignored and
|
||
:djadmin:`makemessages` will generate a warning. For example:
|
||
|
||
.. code-block:: html+django
|
||
|
||
{# Translators: This is ignored #}{% trans "Translate me" %}
|
||
{{ title }}{# Translators: Extracted and associated with 'Welcome' below #}
|
||
<h1>{% trans "Welcome" %}</h1>
|
||
|
||
Quoting in :func:`~django.core.urlresolvers.reverse`
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
When reversing URLs, Django didn't apply :func:`~django.utils.http.urlquote`
|
||
to arguments before interpolating them in URL patterns. This bug is fixed in
|
||
Django 1.6. If you worked around this bug by applying URL quoting before
|
||
passing arguments to :func:`~django.core.urlresolvers.reverse`, this may
|
||
result in double-quoting. If this happens, simply remove the URL quoting from
|
||
your code. You will also have to replace special characters in URLs used in
|
||
:func:`~django.test.SimpleTestCase.assertRedirects` with their encoded versions.
|
||
|
||
Storage of IP addresses in the comments app
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The comments app now uses a
|
||
``GenericIPAddressField`` for storing commenters' IP addresses, to support
|
||
comments submitted from IPv6 addresses. Until now, it stored them in an
|
||
``IPAddressField``, which is only meant to support IPv4. When saving a comment
|
||
made from an IPv6 address, the address would be silently truncated on MySQL
|
||
databases, and raise an exception on Oracle. You will need to change the
|
||
column type in your database to benefit from this change.
|
||
|
||
For MySQL, execute this query on your project's database:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE django_comments MODIFY ip_address VARCHAR(39);
|
||
|
||
For Oracle, execute this query:
|
||
|
||
.. code-block:: sql
|
||
|
||
ALTER TABLE DJANGO_COMMENTS MODIFY (ip_address VARCHAR2(39));
|
||
|
||
If you do not apply this change, the behavior is unchanged: on MySQL, IPv6
|
||
addresses are silently truncated; on Oracle, an exception is generated. No
|
||
database change is needed for SQLite or PostgreSQL databases.
|
||
|
||
Percent literals in ``cursor.execute`` queries
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
When you are running raw SQL queries through the
|
||
:ref:`cursor.execute <executing-custom-sql>` method, the rule about doubling
|
||
percent literals (``%``) inside the query has been unified. Past behavior
|
||
depended on the database backend. Now, across all backends, you only need to
|
||
double literal percent characters if you are also providing replacement
|
||
parameters. For example::
|
||
|
||
# No parameters, no percent doubling
|
||
cursor.execute("SELECT foo FROM bar WHERE baz = '30%'")
|
||
|
||
# Parameters passed, non-placeholders have to be doubled
|
||
cursor.execute("SELECT foo FROM bar WHERE baz = '30%%' and id = %s", [self.id])
|
||
|
||
``SQLite`` users need to check and update such queries.
|
||
|
||
.. _m2m-help_text:
|
||
|
||
Help text of model form fields for ManyToManyField fields
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
HTML rendering of model form fields corresponding to
|
||
:class:`~django.db.models.ManyToManyField` model fields used to get the
|
||
hard-coded sentence:
|
||
|
||
*Hold down "Control", or "Command" on a Mac, to select more than one.*
|
||
|
||
(or its translation to the active locale) imposed as the help legend shown along
|
||
them if neither :attr:`model <django.db.models.Field.help_text>` nor :attr:`form
|
||
<django.forms.Field.help_text>` ``help_text`` attributes were specified by the
|
||
user (or this string was appended to any ``help_text`` that was provided).
|
||
|
||
Since this happened at the model layer, there was no way to prevent the text
|
||
from appearing in cases where it wasn't applicable such as form fields that
|
||
implement user interactions that don't involve a keyboard and/or a mouse.
|
||
|
||
Starting with Django 1.6, as an ad-hoc temporary backward-compatibility
|
||
provision, the logic to add the "Hold down..." sentence has been moved to the
|
||
model form field layer and modified to add the text only when the associated
|
||
widget is :class:`~django.forms.SelectMultiple` or selected subclasses.
|
||
|
||
The change can affect you in a backward incompatible way if you employ custom
|
||
model form fields and/or widgets for ``ManyToManyField`` model fields whose UIs
|
||
do rely on the automatic provision of the mentioned hard-coded sentence. These
|
||
form field implementations need to adapt to the new scenario by providing their
|
||
own handling of the ``help_text`` attribute.
|
||
|
||
Applications that use Django :doc:`model form </topics/forms/modelforms>`
|
||
facilities together with Django built-in form :doc:`fields </ref/forms/fields>`
|
||
and :doc:`widgets </ref/forms/widgets>` aren't affected but need to be aware of
|
||
what's described in :ref:`m2m-help_text-deprecation` below.
|
||
|
||
QuerySet iteration
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``QuerySet`` iteration was changed to immediately convert all fetched
|
||
rows to ``Model`` objects. In Django 1.5 and earlier the fetched rows were
|
||
converted to ``Model`` objects in chunks of 100.
|
||
|
||
Existing code will work, but the amount of rows converted to objects
|
||
might change in certain use cases. Such usages include partially looping
|
||
over a queryset or any usage which ends up doing ``__bool__`` or
|
||
``__contains__``.
|
||
|
||
Notably most database backends did fetch all the rows in one go already in
|
||
1.5.
|
||
|
||
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 colon (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 colon 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=''``. You can also
|
||
customize the ``label_suffix`` on a per-field basis using the new
|
||
``label_suffix`` parameter on :meth:`~django.forms.BoundField.label_tag`.
|
||
|
||
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``.
|
||
|
||
``django.contrib.auth`` password reset uses base 64 encoding of ``User`` PK
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Past versions of Django used base 36 encoding of the ``User`` primary key in
|
||
the password reset views and URLs
|
||
(:func:`django.contrib.auth.views.password_reset_confirm`). Base 36 encoding is
|
||
sufficient if the user primary key is an integer, however, with the
|
||
introduction of custom user models in Django 1.5, that assumption may no longer
|
||
be true.
|
||
|
||
:func:`django.contrib.auth.views.password_reset_confirm` has been modified to
|
||
take a ``uidb64`` parameter instead of ``uidb36``. If you are reversing this
|
||
view, for example in a custom ``password_reset_email.html`` template, be sure
|
||
to update your code.
|
||
|
||
A temporary shim for :func:`django.contrib.auth.views.password_reset_confirm`
|
||
that will allow password reset links generated prior to Django 1.6 to continue
|
||
to work has been added to provide backwards compatibility; this will be removed
|
||
in Django 1.7. Thus, as long as your site has been running Django 1.6 for more
|
||
than :setting:`PASSWORD_RESET_TIMEOUT_DAYS`, this change will have no effect.
|
||
If not (for example, if you upgrade directly from Django 1.5 to Django 1.7),
|
||
then any password reset links generated before you upgrade to Django 1.7 or
|
||
later won't work after the upgrade.
|
||
|
||
In addition, if you have any custom password reset URLs, you will need to
|
||
update them by replacing ``uidb36`` with ``uidb64`` and the dash that follows
|
||
that pattern with a slash. Also add ``_\-`` to the list of characters that may
|
||
match the ``uidb64`` pattern.
|
||
|
||
For example::
|
||
|
||
url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
|
||
'django.contrib.auth.views.password_reset_confirm',
|
||
name='password_reset_confirm'),
|
||
|
||
becomes::
|
||
|
||
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
|
||
'django.contrib.auth.views.password_reset_confirm',
|
||
name='password_reset_confirm'),
|
||
|
||
You may also want to add the shim to support the old style reset links. Using
|
||
the example above, you would modify the existing url by replacing
|
||
``django.contrib.auth.views.password_reset_confirm`` with
|
||
``django.contrib.auth.views.password_reset_confirm_uidb36`` and also remove
|
||
the ``name`` argument so it doesn't conflict with the new url::
|
||
|
||
url(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
|
||
'django.contrib.auth.views.password_reset_confirm_uidb36'),
|
||
|
||
You can remove this url pattern after your app has been deployed with Django
|
||
1.6 for :setting:`PASSWORD_RESET_TIMEOUT_DAYS`.
|
||
|
||
Default session serialization switched to JSON
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Historically, :mod:`django.contrib.sessions` used :mod:`pickle` to serialize
|
||
session data before storing it in the backend. If you're using the :ref:`signed
|
||
cookie session backend<cookie-session-backend>` and :setting:`SECRET_KEY` is
|
||
known by an attacker (there isn't an inherent vulnerability in Django that
|
||
would cause it to leak), the attacker could insert a string into his session
|
||
which, when unpickled, executes arbitrary code on the server. The technique for
|
||
doing so is simple and easily available on the internet. Although the cookie
|
||
session storage signs the cookie-stored data to prevent tampering, a
|
||
:setting:`SECRET_KEY` leak immediately escalates to a remote code execution
|
||
vulnerability.
|
||
|
||
This attack can be mitigated by serializing session data using JSON rather
|
||
than :mod:`pickle`. To facilitate this, Django 1.5.3 introduced a new setting,
|
||
:setting:`SESSION_SERIALIZER`, to customize the session serialization format.
|
||
For backwards compatibility, this setting defaulted to using :mod:`pickle`
|
||
in Django 1.5.3, but we've changed the default to JSON in 1.6. If you upgrade
|
||
and switch from pickle to JSON, sessions created before the upgrade will be
|
||
lost. While JSON serialization does not support all Python objects like
|
||
:mod:`pickle` does, we highly recommend using JSON-serialized sessions. Be
|
||
aware of the following when checking your code to determine if JSON
|
||
serialization will work for your application:
|
||
|
||
* JSON requires string keys, so you will likely run into problems if you are
|
||
using non-string keys in ``request.session``.
|
||
* Setting session expiration by passing ``datetime`` values to
|
||
:meth:`~django.contrib.sessions.backends.base.SessionBase.set_expiry` will
|
||
not work as ``datetime`` values are not serializable in JSON. You can use
|
||
integer values instead.
|
||
|
||
See the :ref:`session_serialization` documentation for more details.
|
||
|
||
Object Relational Mapper changes
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django 1.6 contains many changes to the ORM. These changes fall mostly in
|
||
three categories:
|
||
|
||
1. Bug fixes (e.g. proper join clauses for generic relations, query combining,
|
||
join promotion, and join trimming fixes)
|
||
2. Preparation for new features. For example the ORM is now internally ready
|
||
for multicolumn foreign keys.
|
||
3. General cleanup.
|
||
|
||
These changes can result in some compatibility problems. For example, some
|
||
queries will now generate different table aliases. This can affect
|
||
:meth:`QuerySet.extra() <django.db.models.query.QuerySet.extra>`. In addition
|
||
some queries will now produce different results. An example is
|
||
:meth:`exclude(condition) <django.db.models.query.QuerySet.exclude>`
|
||
where the condition is a complex one (referencing multijoins inside
|
||
:class:`Q objects <django.db.models.Q>`). In many cases the affected
|
||
queries didn't produce correct results in Django 1.5 but do now.
|
||
Unfortunately there are also cases that produce different results, but
|
||
neither Django 1.5 nor 1.6 produce correct results.
|
||
|
||
Finally, there have been many changes to the ORM internal APIs.
|
||
|
||
Miscellaneous
|
||
~~~~~~~~~~~~~
|
||
|
||
* The ``django.db.models.query.EmptyQuerySet`` can't be instantiated any more -
|
||
it is only usable as a marker class for checking if
|
||
:meth:`~django.db.models.query.QuerySet.none` has been called:
|
||
``isinstance(qs.none(), EmptyQuerySet)``
|
||
|
||
* If your CSS/Javascript code used to access HTML input widgets by type, you
|
||
should review it as ``type='text'`` widgets might be now output as
|
||
``type='email'``, ``type='url'`` or ``type='number'`` depending on their
|
||
corresponding field type.
|
||
|
||
* Form field's :attr:`~django.forms.Field.error_messages` that contain a
|
||
placeholder should now always use a named placeholder (``"Value '%(value)s' is
|
||
too big"`` instead of ``"Value '%s' is too big"``). See the corresponding
|
||
field documentation for details about the names of the placeholders. The
|
||
changes in 1.6 particularly affect :class:`~django.forms.DecimalField` and
|
||
:class:`~django.forms.ModelMultipleChoiceField`.
|
||
|
||
* Some :attr:`~django.forms.Field.error_messages` for
|
||
:class:`~django.forms.IntegerField`, :class:`~django.forms.EmailField`,
|
||
``IPAddressField``, :class:`~django.forms.GenericIPAddressField`, and
|
||
:class:`~django.forms.SlugField` have been suppressed because they
|
||
duplicated error messages already provided by validators tied to the fields.
|
||
|
||
* Due to a change in the form validation workflow,
|
||
:class:`~django.forms.TypedChoiceField` ``coerce`` method should always
|
||
return a value present in the ``choices`` field attribute. That limitation
|
||
should be lift again in Django 1.7.
|
||
|
||
* There have been changes in the way timeouts are handled in cache backends.
|
||
Explicitly passing in ``timeout=None`` no longer results in using the
|
||
default timeout. It will now set a non-expiring timeout. Passing 0 into the
|
||
memcache backend no longer uses the default timeout, and now will
|
||
set-and-expire-immediately the value.
|
||
|
||
* The ``django.contrib.flatpages`` app used to set custom HTTP headers for
|
||
debugging purposes. This functionality was not documented and made caching
|
||
ineffective so it has been removed, along with its generic implementation,
|
||
previously available in ``django.core.xheaders``.
|
||
|
||
* The ``XViewMiddleware`` has been moved from ``django.middleware.doc`` to
|
||
``django.contrib.admindocs.middleware`` because it is an implementation
|
||
detail of admindocs, proven not to be reusable in general.
|
||
|
||
* :class:`~django.db.models.GenericIPAddressField` will now only allow
|
||
``blank`` values if ``null`` values are also allowed. Creating a
|
||
``GenericIPAddressField`` where ``blank`` is allowed but ``null`` is not
|
||
will trigger a model validation error because ``blank`` values are always
|
||
stored as ``null``. Previously, storing a ``blank`` value in a field which
|
||
did not allow ``null`` would cause a database exception at runtime.
|
||
|
||
* If a :class:`~django.core.urlresolvers.NoReverseMatch` exception is raised
|
||
from a method when rendering a template, it is not silenced. For example,
|
||
``{{ obj.view_href }}`` will cause template rendering to fail if
|
||
``view_href()`` raises ``NoReverseMatch``. There is no change to the
|
||
:ttag:`{% url %}<url>` tag, it causes template rendering to fail like always
|
||
when ``NoReverseMatch`` is raised.
|
||
|
||
* :meth:`django.test.Client.logout` now calls
|
||
: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.
|
||
|
||
* The admin :attr:`~django.contrib.admin.ModelAdmin.changelist_view` previously
|
||
accepted a ``pop`` GET parameter to signify it was to be displayed in a popup.
|
||
This parameter has been renamed to ``_popup`` to be consistent with the rest
|
||
of the admin views. You should update your custom templates if they use the
|
||
previous parameter name.
|
||
|
||
* :meth:`~django.core.validators.validate_email` now accepts email addresses
|
||
with ``localhost`` as the domain.
|
||
|
||
* The :djadminopt:`--keep-pot` option was added to :djadmin:`makemessages`
|
||
to prevent django from deleting the temporary .pot file it generates before
|
||
creating the .po file.
|
||
|
||
* The undocumented ``django.core.servers.basehttp.WSGIServerException`` has
|
||
been removed. Use ``socket.error`` provided by the standard library instead.
|
||
This change was also released in Django 1.5.5.
|
||
|
||
* The signature of :meth:`django.views.generic.base.RedirectView.get_redirect_url`
|
||
has changed and now accepts positional arguments as well (``*args, **kwargs``).
|
||
Any unnamed captured group will now be passed to ``get_redirect_url()``
|
||
which may result in a ``TypeError`` if you don't update the signature of your
|
||
custom method.
|
||
|
||
.. _deprecated-features-1.6:
|
||
|
||
Features deprecated in 1.6
|
||
==========================
|
||
|
||
Transaction management APIs
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Transaction management was completely overhauled in Django 1.6, and the
|
||
current APIs are deprecated:
|
||
|
||
- ``django.middleware.transaction.TransactionMiddleware``
|
||
- ``django.db.transaction.autocommit``
|
||
- ``django.db.transaction.commit_on_success``
|
||
- ``django.db.transaction.commit_manually``
|
||
- the ``TRANSACTIONS_MANAGED`` setting
|
||
|
||
The reasons for this change and the upgrade path are described in the
|
||
:ref:`transactions documentation <transactions-upgrading-from-1.5>`.
|
||
|
||
``django.contrib.comments``
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Django's comment framework has been deprecated and is no longer supported. It
|
||
will be available in Django 1.6 and 1.7, and removed in Django 1.8. Most users
|
||
will be better served with a custom solution, or a hosted product like Disqus__.
|
||
|
||
The code formerly known as ``django.contrib.comments`` is `still available
|
||
in an external repository`__.
|
||
|
||
__ https://disqus.com/
|
||
__ https://github.com/django/django-contrib-comments
|
||
|
||
Support for PostgreSQL versions older than 8.4
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The end of upstream support periods was reached in December 2011 for
|
||
PostgreSQL 8.2 and in February 2013 for 8.3. As a consequence, Django 1.6 sets
|
||
8.4 as the minimum PostgreSQL version it officially supports.
|
||
|
||
You're strongly encouraged to use the most recent version of PostgreSQL
|
||
available, because of performance improvements and to take advantage of the
|
||
native streaming replication available in PostgreSQL 9.x.
|
||
|
||
Changes to :ttag:`cycle` and :ttag:`firstof`
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The template system generally escapes all variables to avoid XSS attacks.
|
||
However, due to an accident of history, the :ttag:`cycle` and :ttag:`firstof`
|
||
tags render their arguments as-is.
|
||
|
||
Django 1.6 starts a process to correct this inconsistency. The ``future``
|
||
template library provides alternate implementations of :ttag:`cycle` and
|
||
:ttag:`firstof` that autoescape their inputs. If you're using these tags,
|
||
you're encouraged to include the following line at the top of your templates to
|
||
enable the new behavior::
|
||
|
||
{% load cycle from future %}
|
||
|
||
or::
|
||
|
||
{% load firstof from future %}
|
||
|
||
The tags implementing the old behavior have been deprecated, and in Django
|
||
1.8, the old behavior will be replaced with the new behavior. To ensure
|
||
compatibility with future versions of Django, existing templates should be
|
||
modified to use the ``future`` versions.
|
||
|
||
If necessary, you can temporarily disable auto-escaping with
|
||
:func:`~django.utils.safestring.mark_safe` or :ttag:`{% autoescape off %}
|
||
<autoescape>`.
|
||
|
||
``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
``CacheMiddleware`` used to provide a way to cache requests only if they
|
||
weren't made by a logged-in user. This mechanism was largely ineffective
|
||
because the middleware correctly takes into account the ``Vary: Cookie`` HTTP
|
||
header, and this header is being set on a variety of occasions, such as:
|
||
|
||
* accessing the session, or
|
||
* using CSRF protection, which is turned on by default, or
|
||
* using a client-side library which sets cookies, like `Google Analytics`__.
|
||
|
||
This makes the cache effectively work on a per-session basis regardless of the
|
||
``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting.
|
||
|
||
__ http://www.google.com/analytics/
|
||
|
||
``SEND_BROKEN_LINK_EMAILS`` setting
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
:class:`~django.middleware.common.CommonMiddleware` used to provide basic
|
||
reporting of broken links by email when ``SEND_BROKEN_LINK_EMAILS`` is set to
|
||
``True``.
|
||
|
||
Because of intractable ordering problems between
|
||
:class:`~django.middleware.common.CommonMiddleware` and
|
||
:class:`~django.middleware.locale.LocaleMiddleware`, this feature was split
|
||
out into a new middleware:
|
||
:class:`~django.middleware.common.BrokenLinkEmailsMiddleware`.
|
||
|
||
If you're relying on this feature, you should add
|
||
``'django.middleware.common.BrokenLinkEmailsMiddleware'`` to your
|
||
:setting:`MIDDLEWARE_CLASSES` setting and remove ``SEND_BROKEN_LINK_EMAILS``
|
||
from your settings.
|
||
|
||
``_has_changed`` method on widgets
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
If you defined your own form widgets and defined the ``_has_changed`` method
|
||
on a widget, you should now define this method on the form field itself.
|
||
|
||
``module_name`` model _meta attribute
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
``Model._meta.module_name`` was renamed to ``model_name``. Despite being a
|
||
private API, it will go through a regular deprecation path.
|
||
|
||
``get_(add|change|delete)_permission`` model _meta methods
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
``Model._meta.get_(add|change|delete)_permission`` methods were deprecated.
|
||
Even if they were not part of the public API they'll also go through
|
||
a regular deprecation path. You can replace them with
|
||
``django.contrib.auth.get_permission_codename('action', Model._meta)`` where
|
||
``'action'`` is ``'add'``, ``'change'``, or ``'delete'``.
|
||
|
||
``get_query_set`` and similar methods renamed to ``get_queryset``
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Methods that return a ``QuerySet`` such as ``Manager.get_query_set`` or
|
||
``ModelAdmin.queryset`` have been renamed to ``get_queryset``.
|
||
|
||
If you are writing a library that implements, for example, a
|
||
``Manager.get_query_set`` method, and you need to support old Django versions,
|
||
you should rename the method and conditionally add an alias with the old name::
|
||
|
||
class CustomManager(models.Manager):
|
||
def get_queryset(self):
|
||
pass # ...
|
||
|
||
if django.VERSION < (1, 6):
|
||
get_query_set = get_queryset
|
||
|
||
# For Django >= 1.6, models.Manager provides a get_query_set fallback
|
||
# that emits a warning when used.
|
||
|
||
If you are writing a library that needs to call the ``get_queryset`` method and
|
||
must support old Django versions, you should write::
|
||
|
||
get_queryset = (some_manager.get_query_set
|
||
if hasattr(some_manager, 'get_query_set')
|
||
else some_manager.get_queryset)
|
||
return get_queryset() # etc
|
||
|
||
In the general case of a custom manager that both implements its own
|
||
``get_queryset`` method and calls that method, and needs to work with older Django
|
||
versions, and libraries that have not been updated yet, it is useful to define
|
||
a ``get_queryset_compat`` method as below and use it internally to your manager::
|
||
|
||
class YourCustomManager(models.Manager):
|
||
def get_queryset(self):
|
||
return YourCustomQuerySet() # for example
|
||
|
||
get_query_set = get_queryset
|
||
|
||
def active(self): # for example
|
||
return self.get_queryset_compat().filter(active=True)
|
||
|
||
def get_queryset_compat(self):
|
||
get_queryset = (self.get_query_set
|
||
if hasattr(self, 'get_query_set')
|
||
else self.get_queryset)
|
||
return get_queryset()
|
||
|
||
This helps to minimize the changes that are needed, but also works correctly in
|
||
the case of subclasses (such as ``RelatedManagers`` from Django 1.5) which might
|
||
override either ``get_query_set`` or ``get_queryset``.
|
||
|
||
|
||
``shortcut`` view and URLconf
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The ``shortcut`` view was moved from ``django.views.defaults`` to
|
||
``django.contrib.contenttypes.views`` shortly after the 1.0 release, but the
|
||
old location was never deprecated. This oversight was corrected in Django 1.6
|
||
and you should now use the new location.
|
||
|
||
The URLconf ``django.conf.urls.shortcut`` was also deprecated. If you're
|
||
including it in an URLconf, simply replace::
|
||
|
||
(r'^prefix/', include('django.conf.urls.shortcut')),
|
||
|
||
with::
|
||
|
||
(r'^prefix/(?P<content_type_id>\d+)/(?P<object_id>.*)/$', 'django.contrib.contenttypes.views.shortcut'),
|
||
|
||
``ModelForm`` without ``fields`` or ``exclude``
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Previously, if you wanted a :class:`~django.forms.ModelForm` to use all fields on
|
||
the model, you could simply omit the ``Meta.fields`` attribute, and all fields
|
||
would be used.
|
||
|
||
This can lead to security problems where fields are added to the model and,
|
||
unintentionally, automatically become editable by end users. In some cases,
|
||
particular with boolean fields, it is possible for this problem to be completely
|
||
invisible. This is a form of `Mass assignment vulnerability
|
||
<http://en.wikipedia.org/wiki/Mass_assignment_vulnerability>`_.
|
||
|
||
For this reason, this behavior is deprecated, and using the ``Meta.exclude``
|
||
option is strongly discouraged. Instead, all fields that are intended for
|
||
inclusion in the form should be listed explicitly in the ``fields`` attribute.
|
||
|
||
If this security concern really does not apply in your case, there is a shortcut
|
||
to explicitly indicate that all fields should be used - use the special value
|
||
``"__all__"`` for the fields attribute::
|
||
|
||
class MyModelForm(ModelForm):
|
||
class Meta:
|
||
fields = "__all__"
|
||
model = MyModel
|
||
|
||
If you have custom ``ModelForms`` that only need to be used in the admin, there
|
||
is another option. The admin has its own methods for defining fields
|
||
(``fieldsets`` etc.), and so adding a list of fields to the ``ModelForm`` is
|
||
redundant. Instead, simply omit the ``Meta`` inner class of the ``ModelForm``,
|
||
or omit the ``Meta.model`` attribute. Since the ``ModelAdmin`` subclass knows
|
||
which model it is for, it can add the necessary attributes to derive a
|
||
functioning ``ModelForm``. This behavior also works for earlier Django
|
||
versions.
|
||
|
||
``UpdateView`` and ``CreateView`` without explicit fields
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The generic views :class:`~django.views.generic.edit.CreateView` and
|
||
:class:`~django.views.generic.edit.UpdateView`, and anything else derived from
|
||
:class:`~django.views.generic.edit.ModelFormMixin`, are vulnerable to the
|
||
security problem described in the section above, because they can automatically
|
||
create a ``ModelForm`` that uses all fields for a model.
|
||
|
||
For this reason, if you use these views for editing models, you must also supply
|
||
the ``fields`` attribute (new in Django 1.6), which is a list of model fields
|
||
and works in the same way as the :class:`~django.forms.ModelForm`
|
||
``Meta.fields`` attribute. Alternatively, you can set the ``form_class``
|
||
attribute to a ``ModelForm`` that explicitly defines the fields to be used.
|
||
Defining an ``UpdateView`` or ``CreateView`` subclass to be used with a model
|
||
but without an explicit list of fields is deprecated.
|
||
|
||
.. _m2m-help_text-deprecation:
|
||
|
||
Munging of help text of model form fields for ``ManyToManyField`` fields
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
All special handling of the ``help_text`` attribute of ``ManyToManyField`` model
|
||
fields performed by standard model or model form fields as described in
|
||
:ref:`m2m-help_text` above is deprecated and will be removed in Django 1.8.
|
||
|
||
Help text of these fields will need to be handled either by applications, custom
|
||
form fields or widgets, just like happens with the rest of the model field
|
||
types.
|