2015-01-17 07:00:45 +08:00
|
|
|
============================================
|
|
|
|
Django 1.9 release notes - UNDER DEVELOPMENT
|
|
|
|
============================================
|
|
|
|
|
|
|
|
Welcome to Django 1.9!
|
|
|
|
|
|
|
|
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
|
2015-09-20 08:04:50 +08:00
|
|
|
1.8 or older versions. We've :ref:`dropped some features<removed-features-1.9>`
|
|
|
|
that have reached the end of their deprecation cycle, and we've `begun the
|
|
|
|
deprecation process for some features`_.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
.. _`new features`: `What's new in Django 1.9`_
|
|
|
|
.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.9`_
|
|
|
|
.. _`dropped some features`: `Features removed in 1.9`_
|
|
|
|
.. _`begun the deprecation process for some features`: `Features deprecated in 1.9`_
|
|
|
|
|
|
|
|
Python compatibility
|
|
|
|
====================
|
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
Django 1.9 requires Python 2.7, 3.4, or 3.5. We **highly recommend** and only
|
|
|
|
officially support the latest release of each series.
|
|
|
|
|
|
|
|
Since Django 1.8, we've dropped support for Python 3.2 and 3.3, and added
|
|
|
|
support for Python 3.5.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
What's new in Django 1.9
|
|
|
|
========================
|
|
|
|
|
2015-07-01 00:18:56 +08:00
|
|
|
Performing actions after a transaction commit
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The new :func:`~django.db.transaction.on_commit` hook allows performing actions
|
|
|
|
after a database transaction is successfully committed. This is useful for
|
|
|
|
tasks such as sending notification emails, creating queued tasks, or
|
|
|
|
invalidating caches.
|
|
|
|
|
|
|
|
This functionality from the `django-transaction-hooks`_ package has been
|
|
|
|
integrated into Django.
|
|
|
|
|
|
|
|
.. _django-transaction-hooks: https://pypi.python.org/pypi/django-transaction-hooks
|
|
|
|
|
2015-03-08 22:07:57 +08:00
|
|
|
Password validation
|
|
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2015-06-09 01:27:47 +08:00
|
|
|
Django now offers password validation to help prevent the usage of weak
|
2015-03-08 22:07:57 +08:00
|
|
|
passwords by users. The validation is integrated in the included password
|
|
|
|
change and reset forms and is simple to integrate in any other code.
|
|
|
|
Validation is performed by one or more validators, configured in the new
|
|
|
|
:setting:`AUTH_PASSWORD_VALIDATORS` setting.
|
|
|
|
|
|
|
|
Four validators are included in Django, which can enforce a minimum length,
|
|
|
|
compare the password to the user's attributes like their name, ensure
|
2015-06-09 01:27:47 +08:00
|
|
|
passwords aren't entirely numeric, or check against an included list of common
|
2015-03-08 22:07:57 +08:00
|
|
|
passwords. You can combine multiple validators, and some validators have
|
|
|
|
custom configuration options. For example, you can choose to provide a custom
|
2015-06-09 01:27:47 +08:00
|
|
|
list of common passwords. Each validator provides a help text to explain its
|
2015-03-08 22:07:57 +08:00
|
|
|
requirements to the user.
|
|
|
|
|
|
|
|
By default, no validation is performed and all passwords are accepted, so if
|
|
|
|
you don't set :setting:`AUTH_PASSWORD_VALIDATORS`, you will not see any
|
|
|
|
change. In new projects created with the default :djadmin:`startproject`
|
|
|
|
template, a simple set of validators is enabled. To enable basic validation in
|
|
|
|
the included auth forms for your project, you could set, for example::
|
|
|
|
|
|
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
|
|
{
|
|
|
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
|
|
},
|
|
|
|
]
|
|
|
|
|
|
|
|
See :ref:`password-validation` for more details.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-06-12 00:08:48 +08:00
|
|
|
Permission mixins for class-based views
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django now ships with the mixins
|
|
|
|
:class:`~django.contrib.auth.mixins.AccessMixin`,
|
|
|
|
:class:`~django.contrib.auth.mixins.LoginRequiredMixin`,
|
|
|
|
:class:`~django.contrib.auth.mixins.PermissionRequiredMixin`, and
|
|
|
|
:class:`~django.contrib.auth.mixins.UserPassesTestMixin` to provide the
|
|
|
|
functionality of the ``django.contrib.auth.decorators`` for class-based views.
|
|
|
|
These mixins have been taken from, or are at least inspired by, the
|
|
|
|
`django-braces`_ project.
|
|
|
|
|
|
|
|
There are a few differences between Django's and django-braces' implementation,
|
|
|
|
though:
|
|
|
|
|
|
|
|
* The :attr:`~django.contrib.auth.mixins.AccessMixin.raise_exception` attribute
|
|
|
|
can only be ``True`` or ``False``. Custom exceptions or callables are not
|
|
|
|
supported.
|
|
|
|
|
|
|
|
* The :meth:`~django.contrib.auth.mixins.AccessMixin.handle_no_permission`
|
|
|
|
method does not take a ``request`` argument. The current request is available
|
|
|
|
in ``self.request``.
|
|
|
|
|
|
|
|
* The custom ``test_func()`` of :class:`~django.contrib.auth.mixins.UserPassesTestMixin`
|
|
|
|
does not take a ``user`` argument. The current user is available in
|
|
|
|
``self.request.user``.
|
|
|
|
|
|
|
|
* The :attr:`permission_required <django.contrib.auth.mixins.PermissionRequiredMixin>`
|
|
|
|
attribute supports a string (defining one permission) or a list/tuple of
|
|
|
|
strings (defining multiple permissions) that need to be fulfilled to grant
|
|
|
|
access.
|
|
|
|
|
|
|
|
* The new :attr:`~django.contrib.auth.mixins.AccessMixin.permission_denied_message`
|
|
|
|
attribute allows passing a message to the ``PermissionDenied`` exception.
|
|
|
|
|
|
|
|
.. _django-braces: http://django-braces.readthedocs.org/en/latest/index.html
|
|
|
|
|
2015-05-09 01:52:15 +08:00
|
|
|
New styling for ``contrib.admin``
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2015-08-16 04:38:57 +08:00
|
|
|
The admin sports a modern, flat design with new SVG icons which look perfect
|
2015-08-28 07:32:57 +08:00
|
|
|
on HiDPI screens. It still provides a fully-functional experience to `YUI's
|
|
|
|
A-grade`_ browsers. Older browser may experience varying levels of graceful
|
|
|
|
degradation.
|
2015-05-09 01:52:15 +08:00
|
|
|
|
2015-08-08 19:56:37 +08:00
|
|
|
.. _YUI's A-grade: https://github.com/yui/yui3/wiki/Graded-Browser-Support
|
2015-05-09 01:52:15 +08:00
|
|
|
|
2015-02-06 03:31:02 +08:00
|
|
|
Running tests in parallel
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The :djadmin:`test` command now supports a :djadminopt:`--parallel` option to
|
|
|
|
run a project's tests in multiple processes in parallel.
|
|
|
|
|
2015-02-10 05:00:09 +08:00
|
|
|
Each process gets its own database. You must ensure that different test cases
|
|
|
|
don't access the same resources. For instance, test cases that touch the
|
|
|
|
filesystem should create a temporary directory for their own use.
|
|
|
|
|
2015-09-10 21:41:26 +08:00
|
|
|
This option is enabled by default for Django's own test suite provided:
|
|
|
|
|
|
|
|
- the OS supports it (all but Windows)
|
|
|
|
- the database backend supports it (all the built-in backends but Oracle)
|
2015-09-06 17:12:08 +08:00
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Minor features
|
|
|
|
~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
:mod:`django.contrib.admin`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2014-12-27 15:16:53 +08:00
|
|
|
* Admin views now have ``model_admin`` or ``admin_site`` attributes.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-02-08 00:55:47 +08:00
|
|
|
* The URL of the admin change view has been changed (was at
|
|
|
|
``/admin/<app>/<model>/<pk>/`` by default and is now at
|
|
|
|
``/admin/<app>/<model>/<pk>/change/``). This should not affect your
|
|
|
|
application unless you have hardcoded admin URLs. In that case, replace those
|
|
|
|
links by :ref:`reversing admin URLs <admin-reverse-urls>` instead. Note that
|
|
|
|
the old URL still redirects to the new one for backwards compatibility, but
|
|
|
|
it may be removed in a future version.
|
|
|
|
|
2015-03-16 18:00:16 +08:00
|
|
|
* :meth:`ModelAdmin.get_list_select_related()
|
|
|
|
<django.contrib.admin.ModelAdmin.get_list_select_related>` was added to allow
|
|
|
|
changing the ``select_related()`` values used in the admin's changelist query
|
|
|
|
based on the request.
|
|
|
|
|
2015-03-30 18:54:25 +08:00
|
|
|
* The ``available_apps`` context variable, which lists the available
|
|
|
|
applications for the current user, has been added to the
|
|
|
|
:meth:`AdminSite.each_context() <django.contrib.admin.AdminSite.each_context>`
|
|
|
|
method.
|
2015-06-21 07:47:15 +08:00
|
|
|
|
2015-03-13 18:08:03 +08:00
|
|
|
* :attr:`AdminSite.empty_value_display
|
|
|
|
<django.contrib.admin.AdminSite.empty_value_display>` and
|
|
|
|
:attr:`ModelAdmin.empty_value_display
|
|
|
|
<django.contrib.admin.ModelAdmin.empty_value_display>` were added to override
|
|
|
|
the display of empty values in admin change list. You can also customize the
|
|
|
|
value for each field.
|
2015-03-30 18:54:25 +08:00
|
|
|
|
2015-06-19 00:27:58 +08:00
|
|
|
* Added jQuery events :ref:`when an inline form is added or removed
|
|
|
|
<admin-javascript-inline-form-events>` on the change form page.
|
|
|
|
|
2015-06-21 07:47:15 +08:00
|
|
|
* The time picker widget includes a '6 p.m' option for consistency of having
|
|
|
|
predefined options every 6 hours.
|
|
|
|
|
2015-07-13 05:54:30 +08:00
|
|
|
* JavaScript slug generation now supports Romanian characters.
|
|
|
|
|
2014-10-31 03:45:01 +08:00
|
|
|
:mod:`django.contrib.admindocs`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
* The model section of the ``admindocs`` now also describes methods that take
|
|
|
|
arguments, rather than ignoring them.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
:mod:`django.contrib.auth`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-01-17 08:27:10 +08:00
|
|
|
* The default iteration count for the PBKDF2 password hasher has been increased
|
|
|
|
by 20%. This backwards compatible change will not affect users who have
|
|
|
|
subclassed ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
|
|
|
|
default value.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-02-27 03:04:24 +08:00
|
|
|
* The ``BCryptSHA256PasswordHasher`` will now update passwords if its
|
|
|
|
``rounds`` attribute is changed.
|
|
|
|
|
2015-04-03 00:52:45 +08:00
|
|
|
* ``AbstractBaseUser`` and ``BaseUserManager`` were moved to a new
|
|
|
|
``django.contrib.auth.base_user`` module so that they can be imported without
|
2015-09-20 08:04:50 +08:00
|
|
|
including ``django.contrib.auth`` in :setting:`INSTALLED_APPS` (doing so
|
|
|
|
raised a deprecation warning in older versions and is no longer supported in
|
2015-04-03 00:52:45 +08:00
|
|
|
Django 1.9).
|
|
|
|
|
2015-06-05 16:08:19 +08:00
|
|
|
* The permission argument of
|
|
|
|
:func:`~django.contrib.auth.decorators.permission_required()` accepts all
|
|
|
|
kinds of iterables, not only list and tuples.
|
|
|
|
|
2015-06-27 02:59:57 +08:00
|
|
|
* The new :class:`~django.contrib.auth.middleware.PersistentRemoteUserMiddleware`
|
|
|
|
makes it possible to use ``REMOTE_USER`` for setups where the header is only
|
|
|
|
populated on login pages instead of every request in the session.
|
|
|
|
|
2015-06-18 20:49:35 +08:00
|
|
|
* The :func:`~django.contrib.auth.views.password_reset` view accepts an
|
|
|
|
``extra_email_context`` parameter.
|
|
|
|
|
2015-03-27 00:52:11 +08:00
|
|
|
:mod:`django.contrib.contenttypes`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
* It's now possible to use
|
|
|
|
:attr:`~django.db.models.Options.order_with_respect_to` with a
|
|
|
|
``GenericForeignKey``.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
:mod:`django.contrib.gis`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-01-31 03:23:23 +08:00
|
|
|
* All ``GeoQuerySet`` methods have been deprecated and replaced by
|
|
|
|
:doc:`equivalent database functions </ref/contrib/gis/functions>`. As soon
|
|
|
|
as the legacy methods have been replaced in your code, you should even be
|
|
|
|
able to remove the special ``GeoManager`` from your GIS-enabled classes.
|
|
|
|
|
2015-03-14 02:49:02 +08:00
|
|
|
* The GDAL interface now supports instantiating file-based and in-memory
|
|
|
|
:ref:`GDALRaster objects <raster-data-source-objects>` from raw data.
|
|
|
|
Setters for raster properties such as projection or pixel values have
|
|
|
|
been added.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-06-19 23:46:03 +08:00
|
|
|
* For PostGIS users, the new :class:`~django.contrib.gis.db.models.RasterField`
|
|
|
|
allows :ref:`storing GDALRaster objects <creating-and-saving-raster-models>`.
|
|
|
|
It supports automatic spatial index creation and reprojection when saving a
|
|
|
|
model. It does not yet support spatial querying.
|
|
|
|
|
2015-06-19 20:56:50 +08:00
|
|
|
* The new :meth:`GDALRaster.warp() <django.contrib.gis.gdal.GDALRaster.warp>`
|
|
|
|
method allows warping a raster by specifying target raster properties such as
|
|
|
|
origin, width, height, or pixel size (amongst others).
|
|
|
|
|
|
|
|
* The new :meth:`GDALRaster.transform()
|
|
|
|
<django.contrib.gis.gdal.GDALRaster.transform>` method allows transforming a
|
|
|
|
raster into a different spatial reference system by specifying a target
|
|
|
|
``srid``.
|
|
|
|
|
2015-07-30 05:21:03 +08:00
|
|
|
* The new :class:`~django.contrib.gis.geoip2.GeoIP2` class allows using
|
|
|
|
MaxMind's GeoLite2 databases which includes support for IPv6 addresses.
|
|
|
|
|
2015-10-03 18:36:39 +08:00
|
|
|
* The default OpenLayers library version included in widgets has been updated
|
|
|
|
from 2.13 to 2.13.1.
|
|
|
|
|
2015-02-08 23:21:48 +08:00
|
|
|
:mod:`django.contrib.postgres`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-05-21 19:25:50 +08:00
|
|
|
* Added support for the :lookup:`rangefield.contained_by` lookup for some built
|
|
|
|
in fields which correspond to the range fields.
|
2015-06-02 01:00:34 +08:00
|
|
|
|
2015-05-31 05:13:58 +08:00
|
|
|
* Added :class:`~django.contrib.postgres.fields.JSONField`.
|
2015-06-02 01:00:34 +08:00
|
|
|
|
2015-02-08 23:21:48 +08:00
|
|
|
* Added :doc:`/ref/contrib/postgres/aggregates`.
|
|
|
|
|
2015-06-06 04:56:00 +08:00
|
|
|
* Fixed serialization of
|
|
|
|
:class:`~django.contrib.postgres.fields.DateRangeField` and
|
|
|
|
:class:`~django.contrib.postgres.fields.DateTimeRangeField`.
|
|
|
|
|
2015-06-02 01:00:34 +08:00
|
|
|
* Added the :class:`~django.contrib.postgres.functions.TransactionNow` database
|
|
|
|
function.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
:mod:`django.contrib.sessions`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2014-05-17 00:18:34 +08:00
|
|
|
* The session model and ``SessionStore`` classes for the ``db`` and
|
|
|
|
``cached_db`` backends are refactored to allow a custom database session
|
|
|
|
backend to build upon them. See
|
|
|
|
:ref:`extending-database-backed-session-engines` for more details.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
:mod:`django.contrib.sites`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-05-04 06:08:28 +08:00
|
|
|
* :func:`~django.contrib.sites.shortcuts.get_current_site` now handles the case
|
|
|
|
where ``request.get_host()`` returns ``domain:port``, e.g.
|
|
|
|
``example.com:80``. If the lookup fails because the host does not match a
|
|
|
|
record in the database and the host has a port, the port is stripped and the
|
|
|
|
lookup is retried with the domain part only.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
:mod:`django.contrib.syndication`
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-08-21 17:50:43 +08:00
|
|
|
* Support for multiple enclosures per feed item has been added. If multiple
|
|
|
|
enclosures are defined on a RSS feed, an exception is raised as RSS feeds,
|
|
|
|
unlike Atom feeds, do not support multiple enclosures per feed item.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
Cache
|
|
|
|
^^^^^
|
|
|
|
|
2014-11-24 02:33:07 +08:00
|
|
|
* ``django.core.cache.backends.base.BaseCache`` now has a ``get_or_set()``
|
|
|
|
method.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-04-28 05:56:02 +08:00
|
|
|
* :func:`django.views.decorators.cache.never_cache` now sends more persuasive
|
|
|
|
headers (added ``no-cache, no-store, must-revalidate`` to ``Cache-Control``)
|
|
|
|
to better prevent caching.
|
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
CSRF
|
|
|
|
^^^^
|
|
|
|
|
|
|
|
* The request header's name used for CSRF authentication can be customized
|
|
|
|
with :setting:`CSRF_HEADER_NAME`.
|
|
|
|
|
|
|
|
* The CSRF referer header is now validated against the
|
|
|
|
:setting:`CSRF_COOKIE_DOMAIN` setting if set. See :ref:`how-csrf-works` for
|
|
|
|
details.
|
|
|
|
|
|
|
|
* The new :setting:`CSRF_TRUSTED_ORIGINS` setting provides a way to allow
|
|
|
|
cross-origin unsafe requests (e.g. ``POST``) over HTTPS.
|
|
|
|
|
|
|
|
Database backends
|
|
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
* The PostgreSQL backend (``django.db.backends.postgresql_psycopg2``) is also
|
|
|
|
available as ``django.db.backends.postgresql``. The old name will continue to
|
|
|
|
be available for backwards compatibility.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
File Storage
|
|
|
|
^^^^^^^^^^^^
|
|
|
|
|
2015-05-03 12:10:24 +08:00
|
|
|
* :meth:`Storage.get_valid_name()
|
|
|
|
<django.core.files.storage.Storage.get_valid_name>` is now called when
|
|
|
|
the :attr:`~django.db.models.FileField.upload_to` is a callable.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-06-10 22:43:49 +08:00
|
|
|
* :class:`~django.core.files.File` now has the ``seekable()`` method when using
|
|
|
|
Python 3.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Forms
|
|
|
|
^^^^^
|
|
|
|
|
2015-02-07 05:19:23 +08:00
|
|
|
* :class:`~django.forms.ModelForm` accepts the new ``Meta`` option
|
|
|
|
``field_classes`` to customize the type of the fields. See
|
|
|
|
:ref:`modelforms-overriding-default-fields` for details.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-03-16 08:33:59 +08:00
|
|
|
* You can now specify the order in which form fields are rendered with the
|
|
|
|
:attr:`~django.forms.Form.field_order` attribute, the ``field_order``
|
|
|
|
constructor argument , or the :meth:`~django.forms.Form.order_fields` method.
|
|
|
|
|
2015-05-25 02:43:20 +08:00
|
|
|
* A form prefix can be specified inside a form class, not only when
|
|
|
|
instantiating a form. See :ref:`form-prefix` for details.
|
|
|
|
|
2015-06-05 18:42:58 +08:00
|
|
|
* You can now :ref:`specify keyword arguments <custom-formset-form-kwargs>`
|
|
|
|
that you want to pass to the constructor of forms in a formset.
|
|
|
|
|
2015-04-16 06:28:49 +08:00
|
|
|
* :class:`~django.forms.SlugField` now accepts an
|
|
|
|
:attr:`~django.forms.SlugField.allow_unicode` argument to allow Unicode
|
|
|
|
characters in slugs.
|
|
|
|
|
2015-02-05 20:26:15 +08:00
|
|
|
* :class:`~django.forms.CharField` now accepts a
|
|
|
|
:attr:`~django.forms.CharField.strip` argument to strip input data of leading
|
|
|
|
and trailing whitespace. As this defaults to ``True`` this is different
|
|
|
|
behavior from previous releases.
|
|
|
|
|
2015-07-08 03:06:57 +08:00
|
|
|
* Form fields now support the :attr:`~django.forms.Field.disabled` argument,
|
|
|
|
allowing the field widget to be displayed disabled by browsers.
|
|
|
|
|
2015-08-10 16:55:49 +08:00
|
|
|
* It's now possible to customize bound fields by overriding a field's
|
|
|
|
:meth:`~django.forms.Field.get_bound_field()` method.
|
|
|
|
|
2014-12-27 15:16:53 +08:00
|
|
|
Generic Views
|
|
|
|
^^^^^^^^^^^^^
|
|
|
|
|
2015-08-19 04:01:36 +08:00
|
|
|
* Class-based views generated using ``as_view()`` now have ``view_class``
|
2014-12-27 15:16:53 +08:00
|
|
|
and ``view_initkwargs`` attributes.
|
|
|
|
|
2015-08-11 19:35:50 +08:00
|
|
|
* :func:`~django.utils.decorators.method_decorator` can now be used with a list
|
|
|
|
or tuple of decorators. It can also be used to :ref:`decorate classes instead
|
|
|
|
of methods <decorating-class-based-views>`.
|
2015-07-22 04:54:37 +08:00
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Internationalization
|
|
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-03-12 16:32:29 +08:00
|
|
|
* The :func:`django.views.i18n.set_language` view now properly redirects to
|
|
|
|
:ref:`translated URLs <url-internationalization>`, when available.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2014-02-23 22:10:31 +08:00
|
|
|
* The :func:`django.views.i18n.javascript_catalog` view now works correctly
|
|
|
|
if used multiple times with different configurations on the same page.
|
|
|
|
|
2015-03-31 13:58:37 +08:00
|
|
|
* The :func:`django.utils.timezone.make_aware` function gained an ``is_dst``
|
|
|
|
argument to help resolve ambiguous times during DST transitions.
|
|
|
|
|
2014-12-30 22:41:31 +08:00
|
|
|
* You can now use locale variants supported by gettext. These are usually used
|
|
|
|
for languages which can be written in different scripts, for example Latin
|
|
|
|
and Cyrillic (e.g. ``be@latin``).
|
|
|
|
|
2015-06-05 22:10:28 +08:00
|
|
|
* Added the :func:`django.views.i18n.json_catalog` view to help build a custom
|
|
|
|
client-side i18n library upon Django translations. It returns a JSON object
|
|
|
|
containing a translations catalog, formatting settings, and a plural rule.
|
|
|
|
|
2015-05-31 22:20:19 +08:00
|
|
|
* Added the ``name_translated`` attribute to the object returned by the
|
|
|
|
:ttag:`get_language_info` template tag. Also added a corresponding template
|
|
|
|
filter: :tfilter:`language_name_translated`.
|
|
|
|
|
2015-04-16 19:55:37 +08:00
|
|
|
* You can now run :djadmin:`compilemessages` from the root directory of your
|
|
|
|
project and it will find all the app message files that were created by
|
|
|
|
:djadmin:`makemessages`.
|
|
|
|
|
2015-08-25 07:28:23 +08:00
|
|
|
* :djadmin:`makemessages` now calls xgettext once per locale directory rather
|
|
|
|
than once per translatable file. This speeds up localization builds.
|
|
|
|
|
2015-06-12 20:51:28 +08:00
|
|
|
* :ttag:`blocktrans` supports assigning its output to a variable using
|
|
|
|
``asvar``.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Management Commands
|
|
|
|
^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
2015-03-07 20:55:59 +08:00
|
|
|
* The new :djadmin:`sendtestemail` command lets you send a test email to
|
|
|
|
easily confirm that email sending through Django is working.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-03-29 22:59:35 +08:00
|
|
|
* To increase the readability of the SQL code generated by
|
|
|
|
:djadmin:`sqlmigrate`, the SQL code generated for each migration operation is
|
|
|
|
preceded by the operation's description.
|
|
|
|
|
2015-04-02 03:42:09 +08:00
|
|
|
* The :djadmin:`dumpdata` command output is now deterministically ordered.
|
2015-09-24 13:09:41 +08:00
|
|
|
Moreover, when the ``--output`` option is specified, it also shows a progress
|
2015-07-22 05:24:32 +08:00
|
|
|
bar in the terminal.
|
2015-04-02 03:42:09 +08:00
|
|
|
|
2015-04-02 05:33:27 +08:00
|
|
|
* The :djadmin:`createcachetable` command now has a ``--dry-run`` flag to
|
|
|
|
print out the SQL rather than execute it.
|
|
|
|
|
2015-09-07 21:28:15 +08:00
|
|
|
* The :djadmin:`startapp` command creates an ``apps.py`` file.
|
2015-06-13 21:41:56 +08:00
|
|
|
|
2015-06-17 21:37:09 +08:00
|
|
|
* When using the PostgreSQL backend, the :djadmin:`dbshell` command can connect
|
|
|
|
to the database using the password from your settings file (instead of
|
|
|
|
requiring it to be manually entered).
|
|
|
|
|
2015-04-30 23:54:45 +08:00
|
|
|
* The ``django`` package may be run as a script, i.e. ``python -m django``,
|
|
|
|
which will behave the same as ``django-admin``.
|
|
|
|
|
2015-09-07 21:17:55 +08:00
|
|
|
* Management commands that have the ``--noinput`` option now also take
|
|
|
|
``--no-input`` as an alias for that option.
|
|
|
|
|
2015-04-01 04:30:39 +08:00
|
|
|
Migrations
|
|
|
|
^^^^^^^^^^
|
|
|
|
|
|
|
|
* Initial migrations are now marked with an :attr:`initial = True
|
|
|
|
<django.db.migrations.Migration.initial>` class attribute which allows
|
|
|
|
:djadminopt:`migrate --fake-initial <--fake-initial>` to more easily detect
|
|
|
|
initial migrations.
|
|
|
|
|
2015-07-29 00:51:25 +08:00
|
|
|
* Added support for serialization of ``functools.partial`` objects.
|
|
|
|
|
2015-09-12 08:23:10 +08:00
|
|
|
* When supplying ``None`` as a value in :setting:`MIGRATION_MODULES`, Django
|
|
|
|
will consider the app an app without migrations.
|
|
|
|
|
2015-08-27 07:49:35 +08:00
|
|
|
* When applying migrations, the "Rendering model states" step that's displayed
|
|
|
|
when running migrate with verbosity 2 or higher now computes only the states
|
|
|
|
for the migrations that have already been applied. The model states for
|
|
|
|
migrations being applied are generated on demand, drastically reducing the
|
|
|
|
amount of required memory.
|
|
|
|
|
|
|
|
However, this improvement is not available when unapplying migrations and
|
|
|
|
therefore still requires the precomputation and storage of the intermediate
|
|
|
|
migration states.
|
|
|
|
|
|
|
|
This improvement also requires that Django no longer supports mixed migration
|
|
|
|
plans. Mixed plans consist of a list of migrations where some are being
|
|
|
|
applied and others are being unapplied. This was never officially supported
|
|
|
|
and never had a public API that supports this behavior.
|
|
|
|
|
2015-09-12 15:18:24 +08:00
|
|
|
* The :djadmin:`squashmigrations` command now supports specifying the starting
|
|
|
|
migration from which migrations will be squashed.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Models
|
|
|
|
^^^^^^
|
|
|
|
|
2015-06-18 22:12:07 +08:00
|
|
|
* :meth:`QuerySet.bulk_create() <django.db.models.query.QuerySet.bulk_create>`
|
|
|
|
now works on proxy models.
|
|
|
|
|
2015-05-03 03:56:53 +08:00
|
|
|
* Database configuration gained a :setting:`TIME_ZONE <DATABASE-TIME_ZONE>`
|
|
|
|
option for interacting with databases that store datetimes in local time and
|
|
|
|
don't support time zones when :setting:`USE_TZ` is ``True``.
|
|
|
|
|
2015-01-30 02:15:27 +08:00
|
|
|
* Added the :meth:`RelatedManager.set()
|
|
|
|
<django.db.models.fields.related.RelatedManager.set()>` method to the related
|
|
|
|
managers created by ``ForeignKey``, ``GenericForeignKey``, and
|
|
|
|
``ManyToManyField``.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-03-15 09:25:33 +08:00
|
|
|
* The :meth:`~django.db.models.fields.related.RelatedManager.add` method on
|
|
|
|
a reverse foreign key now has a ``bulk`` parameter to allow executing one
|
|
|
|
query regardless of the number of objects being added rather than one query
|
|
|
|
per object.
|
|
|
|
|
2015-02-07 07:16:26 +08:00
|
|
|
* Added the ``keep_parents`` parameter to :meth:`Model.delete()
|
|
|
|
<django.db.models.Model.delete>` to allow deleting only a child's data in a
|
|
|
|
model that uses multi-table inheritance.
|
|
|
|
|
2015-03-07 16:56:25 +08:00
|
|
|
* :meth:`Model.delete() <django.db.models.Model.delete>`
|
|
|
|
and :meth:`QuerySet.delete() <django.db.models.query.QuerySet.delete>` return
|
|
|
|
the number of objects deleted.
|
|
|
|
|
2015-03-17 22:42:53 +08:00
|
|
|
* Added a system check to prevent defining both ``Meta.ordering`` and
|
|
|
|
``order_with_respect_to`` on the same model.
|
|
|
|
|
2015-03-23 04:30:57 +08:00
|
|
|
* :lookup:`Date and time <year>` lookups can be chained with other lookups
|
|
|
|
(such as :lookup:`exact`, :lookup:`gt`, :lookup:`lt`, etc.). For example:
|
|
|
|
``Entry.objects.filter(pub_date__month__gt=6)``.
|
|
|
|
|
2015-05-23 03:16:26 +08:00
|
|
|
* Time lookups (hour, minute, second) are now supported by
|
|
|
|
:class:`~django.db.models.TimeField` for all database backends. Support for
|
|
|
|
backends other than SQLite was added but undocumented in Django 1.7.
|
|
|
|
|
2015-04-24 08:13:24 +08:00
|
|
|
* You can specify the ``output_field`` parameter of the
|
|
|
|
:class:`~django.db.models.Avg` aggregate in order to aggregate over
|
|
|
|
non-numeric columns, such as ``DurationField``.
|
|
|
|
|
2015-03-08 05:20:29 +08:00
|
|
|
* Added the :lookup:`date` lookup to :class:`~django.db.models.DateTimeField`
|
|
|
|
to allow querying the field by only the date portion.
|
|
|
|
|
2015-05-09 19:55:03 +08:00
|
|
|
* Added the :class:`~django.db.models.functions.Greatest` and
|
|
|
|
:class:`~django.db.models.functions.Least` database functions.
|
|
|
|
|
2015-05-29 22:54:10 +08:00
|
|
|
* Added the :class:`~django.db.models.functions.Now` database function, which
|
|
|
|
returns the current date and time.
|
|
|
|
|
2015-08-03 10:30:06 +08:00
|
|
|
* :class:`~django.db.models.Transform` is now a subclass of
|
|
|
|
:ref:`Func() <func-expressions>` which allows ``Transform``\s to be used on
|
|
|
|
the right hand side of an expression, just like regular ``Func``\s. This
|
|
|
|
allows registering some database functions like
|
|
|
|
:class:`~django.db.models.functions.Length`,
|
|
|
|
:class:`~django.db.models.functions.Lower`, and
|
|
|
|
:class:`~django.db.models.functions.Upper` as transforms.
|
|
|
|
|
2015-04-16 06:28:49 +08:00
|
|
|
* :class:`~django.db.models.SlugField` now accepts an
|
|
|
|
:attr:`~django.db.models.SlugField.allow_unicode` argument to allow Unicode
|
|
|
|
characters in slugs.
|
|
|
|
|
2015-08-15 02:22:08 +08:00
|
|
|
* Added support for referencing annotations in ``QuerySet.distinct()``.
|
|
|
|
|
2015-09-13 15:30:35 +08:00
|
|
|
* ``connection.queries`` shows queries with substituted parameters on SQLite.
|
|
|
|
|
2015-08-03 22:34:19 +08:00
|
|
|
* :doc:`Query expressions </ref/models/expressions>` can now be used when
|
|
|
|
creating new model instances using ``save()``, ``create()``, and
|
|
|
|
``bulk_create()``.
|
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
Requests and Responses
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
2015-02-22 05:57:02 +08:00
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
* Unless :attr:`HttpResponse.reason_phrase
|
|
|
|
<django.http.HttpResponse.reason_phrase>` is explicitly set, it now is
|
|
|
|
determined by the current value of :attr:`HttpResponse.status_code
|
|
|
|
<django.http.HttpResponse.status_code>`. Modifying the value of
|
|
|
|
``status_code`` outside of the constructor will also modify the value of
|
|
|
|
``reason_phrase``.
|
2015-02-22 05:57:02 +08:00
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
* The debug view now shows details of chained exceptions on Python 3.
|
2015-03-17 17:52:55 +08:00
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
* The default 40x error views now accept a second positional parameter, the
|
|
|
|
exception that triggered the view.
|
|
|
|
|
|
|
|
* View error handlers now support
|
|
|
|
:class:`~django.template.response.TemplateResponse`, commonly used with
|
|
|
|
class-based views.
|
|
|
|
|
|
|
|
* Exceptions raised by the ``render()`` method are now passed to the
|
|
|
|
``process_exception()`` method of each middleware.
|
|
|
|
|
|
|
|
* Request middleware can now set :attr:`HttpRequest.urlconf
|
|
|
|
<django.http.HttpRequest.urlconf>` to ``None`` to revert any changes made
|
|
|
|
by previous middleware and return to using the :setting:`ROOT_URLCONF`.
|
|
|
|
|
|
|
|
* The :setting:`DISALLOWED_USER_AGENTS` check in
|
|
|
|
:class:`~django.middleware.common.CommonMiddleware` now raises a
|
|
|
|
:class:`~django.core.exceptions.PermissionDenied` exception as opposed to
|
|
|
|
returning an :class:`~django.http.HttpResponseForbidden` so that
|
|
|
|
:data:`~django.conf.urls.handler403` is invoked.
|
|
|
|
|
|
|
|
* Added :meth:`HttpRequest.get_port() <django.http.HttpRequest.get_port>` to
|
|
|
|
fetch the originating port of the request.
|
|
|
|
|
|
|
|
* Added the ``json_dumps_params`` parameter to
|
|
|
|
:class:`~django.http.JsonResponse` to allow passing keyword arguments to the
|
|
|
|
``json.dumps()`` call used to generate the response.
|
|
|
|
|
|
|
|
* The :class:`~django.middleware.common.BrokenLinkEmailsMiddleware` now
|
|
|
|
ignores 404s when the referer is equal to the requested URL. To circumvent
|
|
|
|
the empty referer check already implemented, some Web bots set the referer to
|
|
|
|
the requested URL.
|
2015-09-01 10:32:03 +08:00
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Templates
|
|
|
|
^^^^^^^^^
|
|
|
|
|
2015-01-17 07:34:32 +08:00
|
|
|
* Template tags created with the :meth:`~django.template.Library.simple_tag`
|
|
|
|
helper can now store results in a template variable by using the ``as``
|
|
|
|
argument.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-03-12 00:00:17 +08:00
|
|
|
* Added a :meth:`Context.setdefault() <django.template.Context.setdefault>`
|
|
|
|
method.
|
|
|
|
|
2015-09-12 07:35:21 +08:00
|
|
|
* The :ref:`django.template <django-template-logger>` logger was added and
|
|
|
|
includes the following messages:
|
|
|
|
|
|
|
|
* A ``DEBUG`` level message for missing context variables.
|
|
|
|
|
|
|
|
* A ``WARNING`` level message for uncaught exceptions raised
|
|
|
|
during the rendering of an ``{% include %}`` when debug mode is off
|
|
|
|
(helpful since ``{% include %}`` silences the exception and returns an
|
|
|
|
empty string).
|
2014-04-15 05:18:03 +08:00
|
|
|
|
2015-04-13 23:27:30 +08:00
|
|
|
* The :ttag:`firstof` template tag supports storing the output in a variable
|
|
|
|
using 'as'.
|
|
|
|
|
2015-04-13 22:57:44 +08:00
|
|
|
* :meth:`Context.update() <django.template.Context.update>` can now be used as
|
|
|
|
a context manager.
|
|
|
|
|
2015-03-23 08:22:38 +08:00
|
|
|
* Django template loaders can now extend templates recursively.
|
|
|
|
|
|
|
|
* The debug page template postmortem now include output from each engine that
|
|
|
|
is installed.
|
|
|
|
|
2015-04-25 03:33:03 +08:00
|
|
|
* :ref:`Debug page integration <template-debug-integration>` for custom
|
|
|
|
template engines was added.
|
|
|
|
|
2015-05-09 04:10:36 +08:00
|
|
|
* The :class:`~django.template.backends.django.DjangoTemplates` backend gained
|
|
|
|
the ability to register libraries and builtins explicitly through the
|
|
|
|
template :setting:`OPTIONS <TEMPLATES-OPTIONS>`.
|
|
|
|
|
2015-06-05 06:46:52 +08:00
|
|
|
* The ``timesince`` and ``timeuntil`` filters were improved to deal with leap
|
|
|
|
years when given large time spans.
|
|
|
|
|
2015-06-04 19:50:07 +08:00
|
|
|
* The ``include`` tag now caches parsed templates objects during template
|
|
|
|
rendering, speeding up reuse in places such as for loops.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Tests
|
|
|
|
^^^^^
|
|
|
|
|
2015-05-09 13:33:26 +08:00
|
|
|
* Added the :meth:`json() <django.test.Response.json>` method to test client
|
|
|
|
responses to give access to the response body as JSON.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-06-16 12:35:19 +08:00
|
|
|
* Added the :meth:`~django.test.Client.force_login()` method to the test
|
|
|
|
client. Use this method to simulate the effect of a user logging into the
|
|
|
|
site while skipping the authentication and verification steps of
|
|
|
|
:meth:`~django.test.Client.login()`.
|
|
|
|
|
2015-03-21 20:19:13 +08:00
|
|
|
URLs
|
|
|
|
^^^^
|
|
|
|
|
|
|
|
* Regular expression lookaround assertions are now allowed in URL patterns.
|
|
|
|
|
2015-05-28 23:25:52 +08:00
|
|
|
* The application namespace can now be set using an ``app_name`` attribute
|
|
|
|
on the included module or object. It can also be set by passing a 2-tuple
|
|
|
|
of (<list of patterns>, <application namespace>) as the first argument to
|
|
|
|
:func:`~django.conf.urls.include`.
|
|
|
|
|
2015-09-17 06:07:39 +08:00
|
|
|
* System checks have been added for common URL pattern mistakes.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Validators
|
|
|
|
^^^^^^^^^^
|
|
|
|
|
2015-02-14 22:20:43 +08:00
|
|
|
* Added :func:`django.core.validators.int_list_validator` to generate
|
|
|
|
validators of strings containing integers separated with a custom character.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-04-15 02:42:49 +08:00
|
|
|
* :class:`~django.core.validators.EmailValidator` now limits the length of
|
|
|
|
domain name labels to 63 characters per :rfc:`1034`.
|
|
|
|
|
2015-04-16 06:28:49 +08:00
|
|
|
* Added :func:`~django.core.validators.validate_unicode_slug` to validate slugs
|
|
|
|
that may contain Unicode characters.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Backwards incompatible changes in 1.9
|
|
|
|
=====================================
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
In addition to the changes outlined in this section, be sure to review the
|
2015-09-20 08:04:50 +08:00
|
|
|
:ref:`removed-features-1.9` for the features that have reached the end of
|
|
|
|
their deprecation cycle and therefore 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.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2014-12-30 00:41:16 +08:00
|
|
|
Database backend API
|
|
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
* A couple of new tests rely on the ability of the backend to introspect column
|
|
|
|
defaults (returning the result as ``Field.default``). You can set the
|
|
|
|
``can_introspect_default`` database feature to ``False`` if your backend
|
|
|
|
doesn't implement this. You may want to review the implementation on the
|
|
|
|
backends that Django includes for reference (:ticket:`24245`).
|
|
|
|
|
2015-05-02 21:54:17 +08:00
|
|
|
* Registering a global adapter or converter at the level of the DB-API module
|
|
|
|
to handle time zone information of :class:`~datetime.datetime` values passed
|
|
|
|
as query parameters or returned as query results on databases that don't
|
|
|
|
support time zones is discouraged. It can conflict with other libraries.
|
|
|
|
|
|
|
|
The recommended way to add a time zone to :class:`~datetime.datetime` values
|
|
|
|
fetched from the database is to register a converter for ``DateTimeField``
|
|
|
|
in ``DatabaseOperations.get_db_converters()``.
|
|
|
|
|
2015-05-03 04:26:27 +08:00
|
|
|
The ``needs_datetime_string_cast`` database feature was removed. Database
|
|
|
|
backends that set it must register a converter instead, as explained above.
|
2015-04-12 20:46:24 +08:00
|
|
|
|
2015-05-03 03:27:44 +08:00
|
|
|
* The ``DatabaseOperations.value_to_db_<type>()`` methods were renamed to
|
|
|
|
``adapt_<type>field_value()`` to mirror the ``convert_<type>field_value()``
|
|
|
|
methods.
|
|
|
|
|
2015-03-08 05:20:29 +08:00
|
|
|
* To use the new ``date`` lookup, third-party database backends may need to
|
|
|
|
implement the ``DatabaseOperations.datetime_cast_date_sql()`` method.
|
|
|
|
|
2015-05-23 03:16:26 +08:00
|
|
|
* The ``DatabaseOperations.time_extract_sql()`` method was added. It calls the
|
|
|
|
existing ``date_extract_sql()`` method. This method is overridden by the
|
|
|
|
SQLite backend to add time lookups (hour, minute, second) to
|
|
|
|
:class:`~django.db.models.TimeField`, and may be needed by third-party
|
|
|
|
database backends.
|
2015-02-05 20:26:15 +08:00
|
|
|
|
2015-06-05 00:26:43 +08:00
|
|
|
* The ``DatabaseOperations.datetime_cast_sql()`` method (not to be confused
|
|
|
|
with ``DatabaseOperations.datetime_cast_date_sql()`` mentioned above)
|
|
|
|
has been removed. This method served to format dates on Oracle long
|
|
|
|
before 1.0, but hasn't been overridden by any core backend in years
|
|
|
|
and hasn't been called anywhere in Django's code or tests.
|
2015-05-23 03:16:26 +08:00
|
|
|
|
2015-02-10 05:00:09 +08:00
|
|
|
* In order to support test parallelization, you must implement the
|
2015-09-06 17:12:08 +08:00
|
|
|
``DatabaseCreation._clone_test_db()`` method and set
|
|
|
|
``DatabaseFeatures.can_clone_databases = True``. You may have to adjust
|
2015-02-10 05:00:09 +08:00
|
|
|
``DatabaseCreation.get_test_db_clone_settings()``.
|
|
|
|
|
2015-01-22 00:55:57 +08:00
|
|
|
Default settings that were tuples are now lists
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The default settings in ``django.conf.global_settings`` were a combination of
|
|
|
|
lists and tuples. All settings that were formerly tuples are now lists.
|
|
|
|
|
2015-02-04 05:35:55 +08:00
|
|
|
``is_usable`` attribute on template loaders is removed
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django template loaders previously required an ``is_usable`` attribute to be
|
|
|
|
defined. If a loader was configured in the template settings and this attribute
|
|
|
|
was ``False``, the loader would be silently ignored. In practice, this was only
|
|
|
|
used by the egg loader to detect if setuptools was installed. The ``is_usable``
|
|
|
|
attribute is now removed and the egg loader instead fails at runtime if
|
|
|
|
setuptools is not installed.
|
|
|
|
|
2015-01-30 02:15:27 +08:00
|
|
|
Related set direct assignment
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2015-10-09 05:17:10 +08:00
|
|
|
Direct assignment of related objects in the ORM used to perform a ``clear()``
|
|
|
|
followed by a call to ``add()``. This caused needlessly large data changes and
|
|
|
|
prevented using the :data:`~django.db.models.signals.m2m_changed` signal to
|
|
|
|
track individual changes in many-to-many relations.
|
2015-01-30 02:15:27 +08:00
|
|
|
|
|
|
|
Direct assignment now relies on the the new
|
2015-09-20 08:04:50 +08:00
|
|
|
:meth:`~django.db.models.fields.related.RelatedManager.set` method on related
|
|
|
|
managers which by default only processes changes between the existing related
|
|
|
|
set and the one that's newly assigned. The previous behavior can be restored by
|
|
|
|
replacing direct assignment by a call to ``set()`` with the keyword argument
|
|
|
|
``clear=True``.
|
2015-01-30 02:15:27 +08:00
|
|
|
|
|
|
|
``ModelForm``, and therefore ``ModelAdmin``, internally rely on direct
|
|
|
|
assignment for many-to-many relations and as a consequence now use the new
|
|
|
|
behavior.
|
|
|
|
|
2015-03-03 03:31:14 +08:00
|
|
|
Filesystem-based template loaders catch more specific exceptions
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
When using the :class:`filesystem.Loader <django.template.loaders.filesystem.Loader>`
|
|
|
|
or :class:`app_directories.Loader <django.template.loaders.app_directories.Loader>`
|
|
|
|
template loaders, earlier versions of Django raised a
|
|
|
|
:exc:`~django.template.TemplateDoesNotExist` error if a template source existed
|
|
|
|
but was unreadable. This could happen under many circumstances, such as if
|
|
|
|
Django didn't have permissions to open the file, or if the template source was
|
|
|
|
a directory. Now, Django only silences the exception if the template source
|
|
|
|
does not exist. All other situations result in the original ``IOError`` being
|
|
|
|
raised.
|
|
|
|
|
2015-03-14 06:40:14 +08:00
|
|
|
HTTP redirects no longer forced to absolute URIs
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Relative redirects are no longer converted to absolute URIs. :rfc:`2616`
|
|
|
|
required the ``Location`` header in redirect responses to be an absolute URI,
|
|
|
|
but it has been superseded by :rfc:`7231` which allows relative URIs in
|
|
|
|
``Location``, recognizing the actual practice of user agents, almost all of
|
|
|
|
which support them.
|
|
|
|
|
|
|
|
Consequently, the expected URLs passed to ``assertRedirects`` should generally
|
|
|
|
no longer include the scheme and domain part of the URLs. For example,
|
|
|
|
``self.assertRedirects(response, 'http://testserver/some-url/')`` should be
|
|
|
|
replaced by ``self.assertRedirects(response, '/some-url/')`` (unless the
|
|
|
|
redirection specifically contained an absolute URL, of course).
|
|
|
|
|
2015-03-27 19:53:45 +08:00
|
|
|
Dropped support for PostgreSQL 9.0
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Upstream support for PostgreSQL 9.0 ended in September 2015. As a consequence,
|
|
|
|
Django 1.9 sets 9.1 as the minimum PostgreSQL version it officially supports.
|
|
|
|
|
2015-09-18 19:14:15 +08:00
|
|
|
Dropped support for Oracle 11.1
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Upstream support for Oracle 11.1 ended in August 2015. As a consequence, Django
|
|
|
|
1.9 sets 11.2 as the minimum Oracle version it officially supports.
|
|
|
|
|
2015-03-15 09:25:33 +08:00
|
|
|
Bulk behavior of ``add()`` method of related managers
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
To improve performance, the ``add()`` methods of the related managers created
|
|
|
|
by ``ForeignKey`` and ``GenericForeignKey`` changed from a series of
|
|
|
|
``Model.save()`` calls to a single ``QuerySet.update()`` call. The change means
|
|
|
|
that ``pre_save`` and ``post_save`` signals aren't sent anymore. You can use
|
|
|
|
the ``bulk=False`` keyword argument to revert to the previous behavior.
|
|
|
|
|
2015-03-23 08:22:38 +08:00
|
|
|
Template ``LoaderOrigin`` and ``StringOrigin`` are removed
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In previous versions of Django, when a template engine was initialized with
|
|
|
|
debug as ``True``, an instance of ``django.template.loader.LoaderOrigin`` or
|
|
|
|
``django.template.base.StringOrigin`` was set as the origin attribute on the
|
|
|
|
template object. These classes have been combined into
|
|
|
|
:class:`~django.template.base.Origin` and is now always set regardless of the
|
2015-09-27 01:38:04 +08:00
|
|
|
engine debug setting. For a minimal level of backwards compatibility, the old
|
|
|
|
class names will be kept as aliases to the new ``Origin`` class until
|
|
|
|
Django 2.0.
|
2015-03-23 08:22:38 +08:00
|
|
|
|
2015-03-24 06:17:43 +08:00
|
|
|
.. _default-logging-changes-19:
|
|
|
|
|
|
|
|
Changes to the default logging configuration
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
To make it easier to write custom logging configurations, Django's default
|
|
|
|
logging configuration no longer defines 'django.request' and 'django.security'
|
2015-09-16 02:13:34 +08:00
|
|
|
loggers. Instead, it defines a single 'django' logger, filtered at the ``INFO``
|
|
|
|
level, with two handlers:
|
2015-03-24 06:17:43 +08:00
|
|
|
|
|
|
|
* 'console': filtered at the ``INFO`` level and only active if ``DEBUG=True``.
|
|
|
|
* 'mail_admins': filtered at the ``ERROR`` level and only active if
|
|
|
|
``DEBUG=False``.
|
|
|
|
|
|
|
|
If you aren't overriding Django's default logging, you should see minimal
|
|
|
|
changes in behavior, but you might see some new logging to the ``runserver``
|
|
|
|
console, for example.
|
|
|
|
|
|
|
|
If you are overriding Django's default logging, you should check to see how
|
|
|
|
your configuration merges with the new defaults.
|
|
|
|
|
2015-07-09 23:27:07 +08:00
|
|
|
``HttpRequest`` details in error reporting
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
It was redundant to display the full details of the
|
|
|
|
:class:`~django.http.HttpRequest` each time it appeared as a stack frame
|
|
|
|
variable in the HTML version of the debug page and error email. Thus, the HTTP
|
|
|
|
request will now display the same standard representation as other variables
|
|
|
|
(``repr(request)``). As a result, the method
|
|
|
|
``ExceptionReporterFilter.get_request_repr()`` was removed.
|
|
|
|
|
|
|
|
The contents of the text version of the email were modified to provide a
|
|
|
|
traceback of the same structure as in the case of AJAX requests. The traceback
|
|
|
|
details are rendered by the ``ExceptionReporter.get_traceback_text()`` method.
|
|
|
|
|
2015-05-02 21:54:17 +08:00
|
|
|
Removal of time zone aware global adapters and converters for datetimes
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2015-04-12 20:46:24 +08:00
|
|
|
|
2015-05-02 21:54:17 +08:00
|
|
|
Django no longer registers global adapters and converters for managing time
|
|
|
|
zone information on :class:`~datetime.datetime` values sent to the database as
|
|
|
|
query parameters or read from the database in query results. This change
|
|
|
|
affects projects that meet all the following conditions:
|
2015-04-12 20:46:24 +08:00
|
|
|
|
2015-05-02 21:54:17 +08:00
|
|
|
* The :setting:`USE_TZ` setting is ``True``.
|
|
|
|
* The database is SQLite, MySQL, Oracle, or a third-party database that
|
|
|
|
doesn't support time zones. In doubt, you can check the value of
|
|
|
|
``connection.features.supports_timezones``.
|
|
|
|
* The code queries the database outside of the ORM, typically with
|
|
|
|
``cursor.execute(sql, params)``.
|
|
|
|
|
|
|
|
If you're passing aware :class:`~datetime.datetime` parameters to such
|
|
|
|
queries, you should turn them into naive datetimes in UTC::
|
2015-04-12 20:46:24 +08:00
|
|
|
|
|
|
|
from django.utils import timezone
|
2015-05-02 21:54:17 +08:00
|
|
|
param = timezone.make_naive(param, timezone.utc)
|
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
If you fail to do so, the conversion will be performed as in earlier versions
|
|
|
|
(with a deprecation warning) up until Django 1.11. Django 2.0 won't perform any
|
2015-05-02 21:54:17 +08:00
|
|
|
conversion, which may result in data corruption.
|
|
|
|
|
|
|
|
If you're reading :class:`~datetime.datetime` values from the results, they
|
|
|
|
will be naive instead of aware. You can compensate as follows::
|
|
|
|
|
|
|
|
from django.utils import timezone
|
|
|
|
value = timezone.make_aware(value, timezone.utc)
|
|
|
|
|
|
|
|
You don't need any of this if you're querying the database through the ORM,
|
|
|
|
even if you're using :meth:`raw() <django.db.models.query.QuerySet.raw>`
|
|
|
|
queries. The ORM takes care of managing time zone information.
|
2015-04-12 20:46:24 +08:00
|
|
|
|
2015-05-09 04:10:36 +08:00
|
|
|
Template tag modules are imported when templates are configured
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The :class:`~django.template.backends.django.DjangoTemplates` backend now
|
|
|
|
performs discovery on installed template tag modules when instantiated. This
|
|
|
|
update enables libraries to be provided explicitly via the ``'libraries'``
|
|
|
|
key of :setting:`OPTIONS <TEMPLATES-OPTIONS>` when defining a
|
|
|
|
:class:`~django.template.backends.django.DjangoTemplates` backend. Import
|
|
|
|
or syntax errors in template tag modules now fail early at instantiation time
|
|
|
|
rather than when a template with a :ttag:`{% load %}<load>` tag is first
|
|
|
|
compiled.
|
|
|
|
|
|
|
|
``django.template.base.add_to_builtins()`` is removed
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Although it was a private API, projects commonly used ``add_to_builtins()`` to
|
|
|
|
make template tags and filters available without using the
|
|
|
|
:ttag:`{% load %}<load>` tag. This API has been formalized. Projects should now
|
|
|
|
define built-in libraries via the ``'builtins'`` key of :setting:`OPTIONS
|
|
|
|
<TEMPLATES-OPTIONS>` when defining a
|
|
|
|
:class:`~django.template.backends.django.DjangoTemplates` backend.
|
|
|
|
|
2015-06-15 18:17:09 +08:00
|
|
|
.. _simple-tag-conditional-escape-fix:
|
|
|
|
|
|
|
|
``simple_tag`` now wraps tag output in ``conditional_escape``
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In general, template tags do not autoescape their contents, and this behavior is
|
|
|
|
:ref:`documented <tags-auto-escaping>`. For tags like
|
|
|
|
:class:`~django.template.Library.inclusion_tag`, this is not a problem because
|
|
|
|
the included template will perform autoescaping. For
|
|
|
|
:class:`~django.template.Library.assignment_tag`, the output will be escaped
|
|
|
|
when it is used as a variable in the template.
|
|
|
|
|
|
|
|
For the intended use cases of :class:`~django.template.Library.simple_tag`,
|
|
|
|
however, it is very easy to end up with incorrect HTML and possibly an XSS
|
|
|
|
exploit. For example::
|
|
|
|
|
|
|
|
@register.simple_tag(takes_context=True)
|
|
|
|
def greeting(context):
|
|
|
|
return "Hello {0}!".format(context['request'].user.first_name)
|
|
|
|
|
|
|
|
In older versions of Django, this will be an XSS issue because
|
|
|
|
``user.first_name`` is not escaped.
|
|
|
|
|
|
|
|
In Django 1.9, this is fixed: if the template context has ``autoescape=True``
|
|
|
|
set (the default), then ``simple_tag`` will wrap the output of the tag function
|
|
|
|
with :func:`~django.utils.html.conditional_escape`.
|
|
|
|
|
|
|
|
To fix your ``simple_tag``\s, it is best to apply the following practices:
|
|
|
|
|
|
|
|
* Any code that generates HTML should use either the template system or
|
|
|
|
:func:`~django.utils.html.format_html`.
|
|
|
|
|
|
|
|
* If the output of a ``simple_tag`` needs escaping, use
|
|
|
|
:func:`~django.utils.html.escape` or
|
|
|
|
:func:`~django.utils.html.conditional_escape`.
|
|
|
|
|
|
|
|
* If you are absolutely certain that you are outputting HTML from a trusted
|
|
|
|
source (e.g. a CMS field that stores HTML entered by admins), you can mark it
|
|
|
|
as such using :func:`~django.utils.safestring.mark_safe`.
|
|
|
|
|
|
|
|
Tags that follow these rules will be correct and safe whether they are run on
|
|
|
|
Django 1.9+ or earlier.
|
|
|
|
|
2015-06-07 03:24:02 +08:00
|
|
|
``Paginator.page_range``
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
:attr:`Paginator.page_range <django.core.paginator.Paginator.page_range>` is
|
|
|
|
now an iterator instead of a list.
|
|
|
|
|
|
|
|
In versions of Django previous to 1.8, ``Paginator.page_range`` returned a
|
|
|
|
``list`` in Python 2 and a ``range`` in Python 3. Django 1.8 consistently
|
|
|
|
returned a list, but an iterator is more efficient.
|
|
|
|
|
|
|
|
Existing code that depends on ``list`` specific features, such as indexing,
|
|
|
|
can be ported by converting the iterator into a ``list`` using ``list()``.
|
|
|
|
|
2015-08-19 07:19:01 +08:00
|
|
|
Implicit ``QuerySet`` ``__in`` lookup removed
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In earlier versions, queries such as::
|
|
|
|
|
|
|
|
Model.objects.filter(related_id=RelatedModel.objects.all())
|
|
|
|
|
|
|
|
would implicitly convert to::
|
|
|
|
|
|
|
|
Model.objects.filter(related_id__in=RelatedModel.objects.all())
|
|
|
|
|
|
|
|
resulting in SQL like ``"related_id IN (SELECT id FROM ...)"``.
|
|
|
|
|
|
|
|
This implicit ``__in`` no longer happens so the "IN" SQL is now "=", and if the
|
|
|
|
subquery returns multiple results, at least some databases will throw an error.
|
|
|
|
|
2015-08-18 21:53:51 +08:00
|
|
|
.. _admin-browser-support-19:
|
|
|
|
|
|
|
|
``contrib.admin`` browser support
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The admin no longer supports Internet Explorer 8 and below, as these browsers
|
|
|
|
have reached end-of-life.
|
|
|
|
|
|
|
|
CSS and images to support Internet Explorer 6 and 7 have been removed. PNG and
|
|
|
|
GIF icons have been replaced with SVG icons, which are not supported by
|
|
|
|
Internet Explorer 8 and earlier.
|
|
|
|
|
|
|
|
The jQuery library embedded in the admin has been upgraded from version 1.11.2
|
|
|
|
to 2.1.4. jQuery 2.x has the same API as jQuery 1.x, but does not support
|
|
|
|
Internet Explorer 6, 7, or 8, allowing for better performance and a smaller
|
|
|
|
file size. If you need to support IE8 and must also use the latest version of
|
|
|
|
Django, you can override the admin's copy of jQuery with your own by creating
|
|
|
|
a Django application with this structure::
|
|
|
|
|
|
|
|
app/static/admin/js/vendor/
|
|
|
|
jquery.js
|
|
|
|
jquery.min.js
|
|
|
|
|
2015-10-22 02:59:03 +08:00
|
|
|
.. _syntax-error-old-pip-django-19:
|
|
|
|
|
|
|
|
``SyntaxError`` when installing Django with pip ≤ 1.5.6
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
When installing Django 1.9+ with pip ≤ 1.5.6, you'll see::
|
|
|
|
|
|
|
|
Compiling django/conf/app_template/apps.py ...
|
|
|
|
File "django/conf/app_template/apps.py", line 4
|
|
|
|
class {{ camel_case_app_name }}Config(AppConfig):
|
|
|
|
^
|
|
|
|
SyntaxError: invalid syntax
|
|
|
|
|
|
|
|
Compiling django/conf/app_template/models.py ...
|
|
|
|
File "django/conf/app_template/models.py", line 1
|
|
|
|
{{ unicode_literals }}from django.db import models
|
|
|
|
^
|
|
|
|
SyntaxError: invalid syntax
|
|
|
|
|
|
|
|
It's safe to ignore these errors (Django will still install just fine), and you
|
|
|
|
can avoid them by upgrading pip to a more recent version using
|
|
|
|
``pip install -U pip``.
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
Miscellaneous
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
2015-06-07 07:32:54 +08:00
|
|
|
* The jQuery static files in ``contrib.admin`` have been moved into a
|
|
|
|
``vendor/jquery`` subdirectory.
|
|
|
|
|
2015-03-12 21:40:03 +08:00
|
|
|
* The text displayed for null columns in the admin changelist ``list_display``
|
2015-09-20 08:04:50 +08:00
|
|
|
cells has changed from ``(None)`` (or its translated equivalent) to ``-`` (a
|
|
|
|
dash).
|
2015-03-12 21:40:03 +08:00
|
|
|
|
2015-01-14 03:29:07 +08:00
|
|
|
* ``django.http.responses.REASON_PHRASES`` and
|
|
|
|
``django.core.handlers.wsgi.STATUS_CODE_TEXT`` have been removed. Use
|
|
|
|
Python's stdlib instead: :data:`http.client.responses` for Python 3 and
|
|
|
|
`httplib.responses`_ for Python 2.
|
|
|
|
|
|
|
|
.. _`httplib.responses`: https://docs.python.org/2/library/httplib.html#httplib.responses
|
|
|
|
|
2015-01-30 15:26:13 +08:00
|
|
|
* ``ValuesQuerySet`` and ``ValuesListQuerySet`` have been removed.
|
|
|
|
|
2015-03-05 02:05:17 +08:00
|
|
|
* The ``admin/base.html`` template no longer sets
|
2015-07-21 04:09:42 +08:00
|
|
|
``window.__admin_media_prefix__`` or ``window.__admin_utc_offset__``. Image
|
|
|
|
references in JavaScript that used that value to construct absolute URLs have
|
|
|
|
been moved to CSS for easier customization. The UTC offset is stored on a
|
|
|
|
data attribute of the ``<body>`` tag.
|
2015-03-05 02:05:17 +08:00
|
|
|
|
2015-02-14 22:20:43 +08:00
|
|
|
* ``CommaSeparatedIntegerField`` validation has been refined to forbid values
|
|
|
|
like ``','``, ``',1'``, and ``'1,,2'``.
|
|
|
|
|
2015-04-15 04:50:36 +08:00
|
|
|
* Form initialization was moved from the :meth:`ProcessFormView.get()
|
|
|
|
<django.views.generic.edit.ProcessFormView.get>` method to the new
|
|
|
|
:meth:`FormMixin.get_context_data()
|
|
|
|
<django.views.generic.edit.FormMixin.get_context_data>` method. This may be
|
|
|
|
backwards incompatible if you have overridden the ``get_context_data()``
|
|
|
|
method without calling ``super()``.
|
|
|
|
|
2015-03-17 23:16:50 +08:00
|
|
|
* Support for PostGIS 1.5 has been dropped.
|
|
|
|
|
2015-05-15 01:59:36 +08:00
|
|
|
* The ``django.contrib.sites.models.Site.domain`` field was changed to be
|
|
|
|
:attr:`~django.db.models.Field.unique`.
|
|
|
|
|
2015-04-17 04:19:30 +08:00
|
|
|
* In order to enforce test isolation, database queries are not allowed
|
|
|
|
by default in :class:`~django.test.SimpleTestCase` tests anymore. You
|
|
|
|
can disable this behavior by setting the
|
|
|
|
:attr:`~django.test.SimpleTestCase.allow_database_queries` class attribute
|
|
|
|
to ``True`` on your test class.
|
|
|
|
|
2015-06-04 01:12:27 +08:00
|
|
|
* :attr:`ResolverMatch.app_name
|
|
|
|
<django.core.urlresolvers.ResolverMatch.app_name>` was changed to contain
|
|
|
|
the full namespace path in the case of nested namespaces. For consistency
|
|
|
|
with :attr:`ResolverMatch.namespace
|
|
|
|
<django.core.urlresolvers.ResolverMatch.namespace>`, the empty value is now
|
|
|
|
an empty string instead of ``None``.
|
|
|
|
|
2015-06-05 20:48:41 +08:00
|
|
|
* For security hardening, session keys must be at least 8 characters.
|
|
|
|
|
2015-06-15 22:10:40 +08:00
|
|
|
* Private function ``django.utils.functional.total_ordering()`` has been
|
|
|
|
removed. It contained a workaround for a ``functools.total_ordering()`` bug
|
|
|
|
in Python versions older than 2.7.3.
|
2015-09-06 15:20:35 +08:00
|
|
|
|
2015-06-19 14:42:48 +08:00
|
|
|
* XML serialization (either through :djadmin:`dumpdata` or the syndication
|
|
|
|
framework) used to output any characters it received. Now if the content to
|
|
|
|
be serialized contains any control characters not allowed in the XML 1.0
|
|
|
|
standard, the serialization will fail with a :exc:`ValueError`.
|
2015-06-15 22:10:40 +08:00
|
|
|
|
2015-02-05 20:26:15 +08:00
|
|
|
* :class:`~django.forms.CharField` now strips input of leading and trailing
|
|
|
|
whitespace by default. This can be disabled by setting the new
|
|
|
|
:attr:`~django.forms.CharField.strip` argument to ``False``.
|
|
|
|
|
2015-04-16 05:01:11 +08:00
|
|
|
* Template text that is translated and uses two or more consecutive percent
|
|
|
|
signs, e.g. ``"%%"``, may have a new `msgid` after ``makemessages`` is run
|
|
|
|
(most likely the translation will be marked fuzzy). The new ``msgid`` will be
|
|
|
|
marked ``"#, python-format"``.
|
|
|
|
|
2015-06-26 00:49:50 +08:00
|
|
|
* If neither :attr:`request.current_app <django.http.HttpRequest.current_app>`
|
|
|
|
nor :class:`Context.current_app <django.template.Context>` are set, the
|
|
|
|
:ttag:`url` template tag will now use the namespace of the current request.
|
|
|
|
Set ``request.current_app`` to ``None`` if you don't want to use a namespace
|
|
|
|
hint.
|
|
|
|
|
2015-08-27 03:47:41 +08:00
|
|
|
* The :setting:`SILENCED_SYSTEM_CHECKS` setting now silences messages of all
|
|
|
|
levels. Previously, messages of ``ERROR`` level or higher were printed to the
|
|
|
|
console.
|
|
|
|
|
2015-08-29 03:13:41 +08:00
|
|
|
* The ``FlatPage.enable_comments`` field is removed from the ``FlatPageAdmin``
|
|
|
|
as it's unused by the application. If your project or a third-party app makes
|
|
|
|
use of it, :ref:`create a custom ModelAdmin <flatpages-admin>` to add it back.
|
|
|
|
|
2015-09-06 15:20:35 +08:00
|
|
|
* The return value of
|
|
|
|
:meth:`~django.test.runner.DiscoverRunner.setup_databases` and the first
|
|
|
|
argument of :meth:`~django.test.runner.DiscoverRunner.teardown_databases`
|
|
|
|
changed. They used to be ``(old_names, mirrors)`` tuples. Now they're just
|
|
|
|
the first item, ``old_names``.
|
|
|
|
|
2015-02-06 06:02:10 +08:00
|
|
|
* By default :class:`~django.test.LiveServerTestCase` attempts to find an
|
|
|
|
available port in the 8081-8179 range instead of just trying port 8081.
|
|
|
|
|
2015-09-10 21:05:31 +08:00
|
|
|
* The system checks for :class:`~django.contrib.admin.ModelAdmin` now check
|
|
|
|
instances rather than classes.
|
|
|
|
|
2015-08-27 07:49:35 +08:00
|
|
|
* The private API to apply mixed migration plans has been dropped for
|
|
|
|
performance reasons. Mixed plans consist of a list of migrations where some
|
|
|
|
are being applied and others are being unapplied.
|
|
|
|
|
2015-10-26 20:49:38 +08:00
|
|
|
* The related model object descriptor classes in
|
|
|
|
``django.db.models.fields.related`` (private API) are moved from the
|
|
|
|
``related`` module to ``related_descriptors`` and renamed as follows:
|
|
|
|
|
|
|
|
* ``ReverseSingleRelatedObjectDescriptor`` is ``ForwardManyToOneDescriptor``
|
|
|
|
* ``SingleRelatedObjectDescriptor`` is ``ReverseOneToOneDescriptor``
|
|
|
|
* ``ForeignRelatedObjectsDescriptor`` is ``ReverseManyToOneDescriptor``
|
|
|
|
* ``ManyRelatedObjectsDescriptor`` is ``ManyToManyDescriptor``
|
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
.. _deprecated-features-1.9:
|
|
|
|
|
|
|
|
Features deprecated in 1.9
|
|
|
|
==========================
|
|
|
|
|
2015-01-17 07:34:32 +08:00
|
|
|
``assignment_tag()``
|
|
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django 1.4 added the ``assignment_tag`` helper to ease the creation of
|
|
|
|
template tags that store results in a template variable. The
|
|
|
|
:meth:`~django.template.Library.simple_tag` helper has gained this same
|
|
|
|
ability, making the ``assignment_tag`` obsolete. Tags that use
|
|
|
|
``assignment_tag`` should be updated to use ``simple_tag``.
|
|
|
|
|
2015-03-06 01:38:42 +08:00
|
|
|
``{% cycle %}`` syntax with comma-separated arguments
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The :ttag:`cycle` tag supports an inferior old syntax from previous Django
|
|
|
|
versions:
|
|
|
|
|
|
|
|
.. code-block:: html+django
|
|
|
|
|
|
|
|
{% cycle row1,row2,row3 %}
|
|
|
|
|
|
|
|
Its parsing caused bugs with the current syntax, so support for the old syntax
|
2015-08-19 20:37:27 +08:00
|
|
|
will be removed in Django 1.10 following an accelerated deprecation.
|
2015-03-06 01:38:42 +08:00
|
|
|
|
2015-07-22 22:43:21 +08:00
|
|
|
``ForeignKey`` and ``OneToOneField`` ``on_delete`` argument
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In order to increase awareness about cascading model deletion, the
|
|
|
|
``on_delete`` argument of ``ForeignKey`` and ``OneToOneField`` will be required
|
|
|
|
in Django 2.0.
|
|
|
|
|
|
|
|
Update models and existing migrations to explicitly set the argument. Since the
|
|
|
|
default is ``models.CASCADE``, add ``on_delete=models.CASCADE`` to all
|
|
|
|
``ForeignKey`` and ``OneToOneField``\s that don't use a different option. You
|
|
|
|
can also pass it as the second positional argument if you don't care about
|
|
|
|
compatibility with older versions of Django.
|
|
|
|
|
2015-02-26 22:19:17 +08:00
|
|
|
``Field.rel`` changes
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
``Field.rel`` and its methods and attributes have changed to match the related
|
|
|
|
fields API. The ``Field.rel`` attribute is renamed to ``remote_field`` and many
|
|
|
|
of its methods and attributes are either changed or renamed.
|
|
|
|
|
|
|
|
The aim of these changes is to provide a documented API for relation fields.
|
|
|
|
|
2015-01-30 03:12:08 +08:00
|
|
|
``GeoManager`` and ``GeoQuerySet`` custom methods
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
All custom ``GeoQuerySet`` methods (``area()``, ``distance()``, ``gml()``, ...)
|
|
|
|
have been replaced by equivalent geographic expressions in annotations (see in
|
|
|
|
new features). Hence the need to set a custom ``GeoManager`` to GIS-enabled
|
|
|
|
models is now obsolete. As soon as your code doesn't call any of the deprecated
|
|
|
|
methods, you can simply remove the ``objects = GeoManager()`` lines from your
|
|
|
|
models.
|
|
|
|
|
2015-03-23 08:22:38 +08:00
|
|
|
Template loader APIs have changed
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django template loaders have been updated to allow recursive template
|
|
|
|
extending. This change necessitated a new template loader API. The old
|
|
|
|
``load_template()`` and ``load_template_sources()`` methods are now deprecated.
|
|
|
|
Details about the new API can be found :ref:`in the template loader
|
|
|
|
documentation <custom-template-loaders>`.
|
|
|
|
|
2015-05-28 23:25:52 +08:00
|
|
|
Passing a 3-tuple or an ``app_name`` to :func:`~django.conf.urls.include()`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2015-09-23 20:14:13 +08:00
|
|
|
The instance namespace part of passing a tuple as an argument to ``include()``
|
|
|
|
has been replaced by passing the ``namespace`` argument to ``include()``. For
|
|
|
|
example::
|
2015-05-28 23:25:52 +08:00
|
|
|
|
2015-09-23 20:14:13 +08:00
|
|
|
polls_patterns = [
|
|
|
|
url(...),
|
|
|
|
]
|
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
url(r'^polls/', include((polls_patterns, 'polls', 'author-polls'))),
|
|
|
|
]
|
|
|
|
|
|
|
|
becomes::
|
|
|
|
|
|
|
|
polls_patterns = ([
|
|
|
|
url(...),
|
|
|
|
], 'polls') # 'polls' is the app_name
|
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
url(r'^polls/', include(polls_patterns, namespace='author-polls')),
|
|
|
|
]
|
|
|
|
|
|
|
|
The ``app_name`` argument to ``include()`` has been replaced by passing a
|
|
|
|
2-tuple (as above), or passing an object or module with an ``app_name``
|
|
|
|
attribute (as below). If the ``app_name`` is set in this new way, the
|
|
|
|
``namespace`` argument is no longer required. It will default to the value of
|
|
|
|
``app_name``. For example, the URL patterns in the tutorial are changed from:
|
|
|
|
|
|
|
|
.. snippet::
|
|
|
|
:filename: mysite/urls.py
|
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
url(r'^polls/', include('polls.urls', namespace="polls")),
|
|
|
|
...
|
|
|
|
]
|
|
|
|
|
|
|
|
to:
|
|
|
|
|
|
|
|
.. snippet::
|
|
|
|
:filename: mysite/urls.py
|
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
url(r'^polls/', include('polls.urls')), # 'namespace="polls"' removed
|
|
|
|
...
|
|
|
|
]
|
|
|
|
|
|
|
|
.. snippet::
|
|
|
|
:filename: polls/urls.py
|
|
|
|
|
|
|
|
app_name = 'polls' # added
|
|
|
|
urlpatterns = [...]
|
2015-05-28 23:25:52 +08:00
|
|
|
|
|
|
|
This change also means that the old way of including an ``AdminSite`` instance
|
|
|
|
is deprecated. Instead, pass ``admin.site.urls`` directly to
|
|
|
|
:func:`~django.conf.urls.url()`:
|
|
|
|
|
|
|
|
.. snippet::
|
|
|
|
:filename: urls.py
|
|
|
|
|
|
|
|
from django.conf.urls import url
|
|
|
|
from django.contrib import admin
|
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
url(r'^admin/', admin.site.urls),
|
|
|
|
]
|
|
|
|
|
|
|
|
URL application namespace required if setting an instance namespace
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In the past, an instance namespace without an application namespace
|
|
|
|
would serve the same purpose as the application namespace, but it was
|
|
|
|
impossible to reverse the patterns if there was an application namespace
|
|
|
|
with the same name. Includes that specify an instance namespace require that
|
|
|
|
the included URLconf sets an application namespace.
|
|
|
|
|
2015-06-05 23:42:05 +08:00
|
|
|
``current_app`` parameter to ``contrib.auth`` views
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
All views in ``django.contrib.auth.views`` have the following structure::
|
|
|
|
|
|
|
|
def view(request, ..., current_app=None, ...):
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
if current_app is not None:
|
|
|
|
request.current_app = current_app
|
|
|
|
|
|
|
|
return TemplateResponse(request, template_name, context)
|
|
|
|
|
|
|
|
As of Django 1.8, ``current_app`` is set on the ``request`` object. For
|
|
|
|
consistency, these views will require the caller to set ``current_app`` on the
|
|
|
|
``request`` instead of passing it in a separate argument.
|
|
|
|
|
2015-07-31 01:24:08 +08:00
|
|
|
``django.contrib.gis.geoip``
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The :mod:`django.contrib.gis.geoip2` module supersedes
|
|
|
|
``django.contrib.gis.geoip``. The new module provides a similar API except that
|
|
|
|
it doesn't provide the legacy GeoIP-Python API compatibility methods.
|
|
|
|
|
2015-01-22 02:26:51 +08:00
|
|
|
Miscellaneous
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
* The ``weak`` argument to ``django.dispatch.signals.Signal.disconnect()`` has
|
|
|
|
been deprecated as it has no effect.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
2015-01-27 12:29:06 +08:00
|
|
|
* The ``check_aggregate_support()`` method of
|
|
|
|
``django.db.backends.base.BaseDatabaseOperations`` has been deprecated and
|
2015-06-23 01:54:35 +08:00
|
|
|
will be removed in Django 2.0. The more general ``check_expression_support()``
|
2015-01-27 12:29:06 +08:00
|
|
|
should be used instead.
|
|
|
|
|
2015-01-28 02:50:00 +08:00
|
|
|
* ``django.forms.extras`` is deprecated. You can find
|
2015-01-26 11:28:57 +08:00
|
|
|
:class:`~django.forms.SelectDateWidget` in ``django.forms.widgets``
|
|
|
|
(or simply ``django.forms``) instead.
|
|
|
|
|
2015-03-03 16:43:56 +08:00
|
|
|
* Private API ``django.db.models.fields.add_lazy_relation()`` is deprecated.
|
|
|
|
|
2015-04-07 03:02:34 +08:00
|
|
|
* The ``django.contrib.auth.tests.utils.skipIfCustomUser()`` decorator is
|
|
|
|
deprecated. With the test discovery changes in Django 1.6, the tests for
|
|
|
|
``django.contrib`` apps are no longer run as part of the user's project.
|
|
|
|
Therefore, the ``@skipIfCustomUser`` decorator is no longer needed to
|
|
|
|
decorate tests in ``django.contrib.auth``.
|
|
|
|
|
2015-04-22 03:54:00 +08:00
|
|
|
* If you customized some :ref:`error handlers <error-views>`, the view
|
|
|
|
signatures with only one request parameter are deprecated. The views should
|
|
|
|
now also accept a second ``exception`` positional parameter.
|
|
|
|
|
2015-06-04 22:00:39 +08:00
|
|
|
* The ``django.utils.feedgenerator.Atom1Feed.mime_type`` and
|
|
|
|
``django.utils.feedgenerator.RssFeed.mime_type`` attributes are deprecated in
|
|
|
|
favor of ``content_type``.
|
|
|
|
|
2014-06-10 06:15:21 +08:00
|
|
|
* :class:`~django.core.signing.Signer` now issues a warning if an invalid
|
|
|
|
separator is used. This will become an exception in Django 1.10.
|
|
|
|
|
2015-04-26 14:30:46 +08:00
|
|
|
* ``django.db.models.Field._get_val_from_obj()`` is deprecated in favor of
|
|
|
|
``Field.value_from_object()``.
|
|
|
|
|
2015-07-16 21:32:42 +08:00
|
|
|
* ``django.template.loaders.eggs.Loader`` is deprecated as distributing
|
|
|
|
applications as eggs is not recommended.
|
|
|
|
|
2015-07-29 23:12:07 +08:00
|
|
|
* The ``callable_obj`` keyword argument to
|
|
|
|
``SimpleTestCase.assertRaisesMessage()`` is deprecated. Pass the callable as
|
|
|
|
a positional argument instead.
|
|
|
|
|
2015-09-09 03:46:26 +08:00
|
|
|
* The ``allow_tags`` attribute on methods of ``ModelAdmin`` has been
|
|
|
|
deprecated. Use :func:`~django.utils.html.format_html`,
|
|
|
|
:func:`~django.utils.html.format_html_join`, or
|
|
|
|
:func:`~django.utils.safestring.mark_safe` when constructing the method's
|
|
|
|
return value instead.
|
|
|
|
|
2015-08-21 17:50:43 +08:00
|
|
|
* The ``enclosure`` keyword argument to ``SyndicationFeed.add_item()`` is
|
|
|
|
deprecated. Use the new ``enclosures`` argument which accepts a list of
|
|
|
|
``Enclosure`` objects instead of a single one.
|
|
|
|
|
2015-09-27 01:38:04 +08:00
|
|
|
* The ``django.template.loader.LoaderOrigin`` and
|
|
|
|
``django.template.base.StringOrigin`` aliases for
|
|
|
|
``django.template.base.Origin`` are deprecated.
|
|
|
|
|
2015-09-20 08:04:50 +08:00
|
|
|
.. _removed-features-1.9:
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
Features removed in 1.9
|
|
|
|
=======================
|
|
|
|
|
|
|
|
These features have reached the end of their deprecation cycle and so have been
|
|
|
|
removed in Django 1.9 (please see the :ref:`deprecation timeline
|
|
|
|
<deprecation-removed-in-1.9>` for more details):
|
|
|
|
|
|
|
|
* ``django.utils.dictconfig`` is removed.
|
|
|
|
|
|
|
|
* ``django.utils.importlib`` is removed.
|
|
|
|
|
|
|
|
* ``django.utils.tzinfo`` is removed.
|
|
|
|
|
|
|
|
* ``django.utils.unittest`` is removed.
|
|
|
|
|
|
|
|
* The ``syncdb`` command is removed.
|
|
|
|
|
|
|
|
* ``django.db.models.signals.pre_syncdb`` and
|
|
|
|
``django.db.models.signals.post_syncdb`` is removed.
|
|
|
|
|
|
|
|
* Support for ``allow_syncdb`` on database routers is removed.
|
|
|
|
|
2015-08-31 22:33:52 +08:00
|
|
|
* Automatic syncing of apps without migrations is removed. Migrations are
|
|
|
|
compulsory for all apps unless you pass the :djadminopt:`--run-syncdb`
|
|
|
|
option to ``migrate``.
|
|
|
|
|
|
|
|
* Support for automatic loading of ``initial_data`` fixtures and initial SQL
|
|
|
|
data is removed.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
* All models need to be defined inside an installed application or declare an
|
|
|
|
explicit :attr:`~django.db.models.Options.app_label`. Furthermore, it isn't
|
|
|
|
possible to import them before their application is loaded. In particular, it
|
|
|
|
isn't possible to import models inside the root package of an application.
|
|
|
|
|
|
|
|
* The model and form ``IPAddressField`` is removed. A stub field remains for
|
|
|
|
compatibility with historical migrations.
|
|
|
|
|
|
|
|
* ``AppCommand.handle_app()`` is no longer be supported.
|
|
|
|
|
2015-01-19 10:57:38 +08:00
|
|
|
* ``RequestSite`` and ``get_current_site()`` are no longer importable from
|
|
|
|
``django.contrib.sites.models``.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
* FastCGI support via the ``runfcgi`` management command is removed.
|
|
|
|
|
|
|
|
* ``django.utils.datastructures.SortedDict`` is removed.
|
|
|
|
|
|
|
|
* ``ModelAdmin.declared_fieldsets`` is removed.
|
|
|
|
|
2015-01-19 10:57:38 +08:00
|
|
|
* The ``util`` modules that provided backwards compatibility are removed:
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
* ``django.contrib.admin.util``
|
|
|
|
* ``django.contrib.gis.db.backends.util``
|
|
|
|
* ``django.db.backends.util``
|
|
|
|
* ``django.forms.util``
|
|
|
|
|
|
|
|
* ``ModelAdmin.get_formsets`` is removed.
|
|
|
|
|
|
|
|
* The backward compatible shims introduced to rename the
|
|
|
|
``BaseMemcachedCache._get_memcache_timeout()`` method to
|
|
|
|
``get_backend_timeout()`` is removed.
|
|
|
|
|
|
|
|
* The ``--natural`` and ``-n`` options for :djadmin:`dumpdata` are removed.
|
|
|
|
|
|
|
|
* The ``use_natural_keys`` argument for ``serializers.serialize()`` is removed.
|
|
|
|
|
2015-01-19 10:57:38 +08:00
|
|
|
* Private API ``django.forms.forms.get_declared_fields()`` is removed.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
* The ability to use a ``SplitDateTimeWidget`` with ``DateTimeField`` is
|
|
|
|
removed.
|
|
|
|
|
|
|
|
* The ``WSGIRequest.REQUEST`` property is removed.
|
|
|
|
|
|
|
|
* The class ``django.utils.datastructures.MergeDict`` is removed.
|
|
|
|
|
|
|
|
* The ``zh-cn`` and ``zh-tw`` language codes are removed.
|
|
|
|
|
|
|
|
* The internal ``django.utils.functional.memoize()`` is removed.
|
|
|
|
|
|
|
|
* ``django.core.cache.get_cache`` is removed.
|
|
|
|
|
|
|
|
* ``django.db.models.loading`` is removed.
|
|
|
|
|
|
|
|
* Passing callable arguments to querysets is no longer possible.
|
|
|
|
|
|
|
|
* ``BaseCommand.requires_model_validation`` is removed in favor of
|
|
|
|
``requires_system_checks``. Admin validators is replaced by admin checks.
|
|
|
|
|
2015-01-19 10:57:38 +08:00
|
|
|
* The ``ModelAdmin.validator_class`` and ``default_validator_class`` attributes
|
|
|
|
are removed.
|
|
|
|
|
|
|
|
* ``ModelAdmin.validate()`` is removed.
|
2015-01-17 07:00:45 +08:00
|
|
|
|
|
|
|
* ``django.db.backends.DatabaseValidation.validate_field`` is removed in
|
|
|
|
favor of the ``check_field`` method.
|
|
|
|
|
2015-04-02 04:42:44 +08:00
|
|
|
* The ``validate`` management command is removed.
|
2015-01-18 08:14:44 +08:00
|
|
|
|
2015-01-17 07:00:45 +08:00
|
|
|
* ``django.utils.module_loading.import_by_path`` is removed in favor of
|
|
|
|
``django.utils.module_loading.import_string``.
|
|
|
|
|
|
|
|
* ``ssi`` and ``url`` template tags are removed from the ``future`` template
|
|
|
|
tag library.
|
|
|
|
|
|
|
|
* ``django.utils.text.javascript_quote()`` is removed.
|
|
|
|
|
|
|
|
* Database test settings as independent entries in the database settings,
|
|
|
|
prefixed by ``TEST_``, are no longer supported.
|
|
|
|
|
|
|
|
* The `cache_choices` option to :class:`~django.forms.ModelChoiceField` and
|
|
|
|
:class:`~django.forms.ModelMultipleChoiceField` is removed.
|
|
|
|
|
|
|
|
* The default value of the
|
|
|
|
:attr:`RedirectView.permanent <django.views.generic.base.RedirectView.permanent>`
|
|
|
|
attribute has changed from ``True`` to ``False``.
|
|
|
|
|
|
|
|
* ``django.contrib.sitemaps.FlatPageSitemap`` is removed in favor of
|
|
|
|
``django.contrib.flatpages.sitemaps.FlatPageSitemap``.
|
2015-01-19 10:57:38 +08:00
|
|
|
|
|
|
|
* Private API ``django.test.utils.TestTemplateLoader`` is removed.
|
|
|
|
|
|
|
|
* The ``django.contrib.contenttypes.generic`` module is removed.
|