============================================
Django 1.8 release notes - UNDER DEVELOPMENT
============================================

Welcome to Django 1.8!

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.6 or older versions. We've also dropped some features, which are detailed in
:ref:`our deprecation plan <deprecation-removed-in-1.8>`, and we've `begun the
deprecation process for some features`_.

.. _`new features`: `What's new in Django 1.8`_
.. _`backwards incompatible changes`: `Backwards incompatible changes in 1.8`_
.. _`begun the deprecation process for some features`: `Features deprecated in 1.8`_

Python compatibility
====================

Like Django 1.7, Django 1.8 requires Python 2.7 or above, though we
**highly recommend** the latest minor release.

What's new in Django 1.8
========================

...

Minor features
~~~~~~~~~~~~~~

:mod:`django.contrib.admin`
^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.auth`
^^^^^^^^^^^^^^^^^^^^^^^^^^

* Authorization backends can now raise
  :class:`~django.core.exceptions.PermissionDenied` in
  :meth:`~django.contrib.auth.models.User.has_perm`
  and :meth:`~django.contrib.auth.models.User.has_module_perms`
  to short-circuit permission checking.

:mod:`django.contrib.formtools`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* A :doc:`form wizard </ref/contrib/formtools/form-wizard>` using the
  :class:`~django.contrib.formtools.wizard.views.CookieWizardView` will now ignore
  an invalid cookie, and the wizard will restart from the first step. An invalid
  cookie can occur in cases of intentional manipulation, but also after a secret
  key change. Previously, this would raise ``WizardViewCookieModified``, a
  ``SuspiciousOperation``, causing an exception for any user with an invalid cookie
  upon every request to the wizard, until the cookie is removed.

:mod:`django.contrib.gis`
^^^^^^^^^^^^^^^^^^^^^^^^^^

* Compatibility shims for ``SpatialRefSys`` and ``GeometryColumns`` changed in
  Django 1.2 have been removed.

:mod:`django.contrib.messages`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.redirects`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.sessions`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* Session cookie is now deleted after
  :meth:`~django.contrib.sessions.backends.base.SessionBase.flush()` is called.

:mod:`django.contrib.sitemaps`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.sites`
^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.staticfiles`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

:mod:`django.contrib.syndication`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ...

Cache
^^^^^

* ...

Email
^^^^^

* :ref:`Email backends <topic-email-backends>` now support the context manager
  protocol for opening and closing connections.

File Storage
^^^^^^^^^^^^

* ...

File Uploads
^^^^^^^^^^^^

* ...

Forms
^^^^^

* Form widgets now render attributes with a value of ``True`` or ``False``
  as HTML5 boolean attributes.

* The new :meth:`~django.forms.Form.has_error()` method allows checking
  if a specific error has happened.

* If :attr:`~django.forms.Form.required_css_class` is defined on a form, then
  the ``<label>`` tags for required fields will have this class present in its
  attributes.

* :class:`~django.forms.Field` now accepts a
  :attr:`~django.forms.Field.label_suffix` argument, which will override the
  form's :attr:`~django.forms.Form.label_suffix`. This enables customizing the
  suffix on a per-field basis — previously it wasn't possible to override
  a form's :attr:`~django.forms.Form.label_suffix` while using  shortcuts such
  as ``{{ form.as_p }}`` in templates.

* :class:`~django.forms.extras.widgets.SelectDateWidget` now accepts an
  :attr:`~django.forms.extras.widgets.SelectDateWidget.empty_label` argument, which will
  override the top list choice label when :class:`~django.forms.DateField` is not required.

Internationalization
^^^^^^^^^^^^^^^^^^^^

* :setting:`FORMAT_MODULE_PATH` can now be a list of strings representing
  module paths. This allows importing several format modules from different
  reusable apps. It also allows overriding those custom formats in your main
  Django project.

Management Commands
^^^^^^^^^^^^^^^^^^^

* :djadmin:`dumpdata` now has the option :djadminopt:`--output` which allows
  specifying the file to which the serialized data is written.

* :djadmin:`makemessages` and :djadmin:`compilemessages` now have the option
  :djadminopt:`--exclude` which allows exclusion of specific locales from
  processing.

* The :djadminopt:`--ignorenonexistent` option of the :djadmin:`loaddata`
  management command now ignores data for models that no longer exist.

Models
^^^^^^

* ...

Signals
^^^^^^^

* Exceptions from the ``(receiver, exception)`` tuples returned by
  :meth:`Signal.send_robust() <django.dispatch.Signal.send_robust>` now have
  their traceback attached as a ``__traceback__`` attribute.

Templates
^^^^^^^^^

* ...

Requests and Responses
^^^^^^^^^^^^^^^^^^^^^^

* ...

Tests
^^^^^

* The ``count`` argument was added to
  :meth:`~django.test.SimpleTestCase.assertTemplateUsed`. This allows you to
  assert that a template was rendered a specific number of times.

* The new :meth:`~django.test.SimpleTestCase.assertJSONNotEqual` assertion
  allows you to test that two JSON fragments are not equal.

* Added the ability to preserve the test database by adding the :djadminopt:`--keepdb`
  flag.

Validators
^^^^^^^^^^

* ...

Backwards incompatible changes in 1.8
=====================================

.. warning::

    In addition to the changes outlined in this section, be sure to review the
    :ref:`deprecation plan <deprecation-removed-in-1.8>` 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.

* Some operations on related objects such as
  :meth:`~django.db.models.fields.related.RelatedManager.add()` or
  :ref:`direct assignment<direct-assignment>` ran multiple data modifying
  queries without wrapping them in transactions. To reduce the risk of data
  corruption, all data modifying methods that affect multiple related objects
  (i.e. ``add()``, ``remove()``, ``clear()``, and
  :ref:`direct assignment<direct-assignment>`) now perform their data modifying
  queries from within a transaction, provided your database supports
  transactions.

  This has one backwards incompatible side effect, signal handlers triggered
  from these methods are now executed within the method's transaction and
  any exception in a signal handler will prevent the whole operation.

Miscellaneous
~~~~~~~~~~~~~

* ``URLField.to_python`` no longer adds a trailing slash to pathless URLs.

* ``django.contrib.gis`` dropped support for GEOS 3.1 and GDAL 1.6.

.. _deprecated-features-1.8:

Features deprecated in 1.8
==========================

Loading ``cycle`` and ``firstof`` template tags from ``future`` library
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Django 1.6 introduced ``{% load cycle from future %}`` and
``{% load firstof from future %}`` syntax for forward compatibility of the
:ttag:`cycle` and :ttag:`firstof` template tags. This syntax is now deprecated
and will be removed in Django 2.0. You can simply remove the
``{% load ... from future %}`` tags.

``django.conf.urls.patterns()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In the olden days of Django, it was encouraged to reference views as strings
in ``urlpatterns``::

    urlpatterns = patterns('',
        url('^$', 'myapp.views.myview'),
    )

and Django would magically import ``myapp.views.myview`` internally and turn
the string into a real function reference. In order to reduce repetition when
referencing many views from the same module, the ``patterns()`` function takes
a required initial ``prefix`` argument which is prepended to all
views-as-strings in that set of ``urlpatterns``::

    urlpatterns = patterns('myapp.views',
        url('^$', 'myview'),
        url('^other/$', 'otherview'),
    )

In the modern era, we have updated the tutorial to instead recommend importing
your views module and referencing your view functions (or classes) directly.
This has a number of advantages, all deriving from the fact that we are using
normal Python in place of "Django String Magic": the errors when you mistype a
view name are less obscure, IDEs can help with autocompletion of view names,
etc.

So these days, the above use of the ``prefix`` arg is much more likely to be
written (and is better written) as::

    from myapp import views

    urlpatterns = patterns('',
        url('^$', views.myview),
        url('^other/$', views.otherview),
    )

Thus ``patterns()`` serves little purpose and is a burden when teaching new users
(answering the newbie's question "why do I need this empty string as the first
argument to ``patterns()``?"). For these reasons, we are deprecating it.
Updating your code is as simple as ensuring that ``urlpatterns`` is a list of
:func:`django.conf.urls.url` instances. For example::

    from django.conf.urls import url
    from myapp import views

    urlpatterns = [
        url('^$', views.myview),
        url('^other/$', views.otherview),
    ]

``django.test.SimpleTestCase.urls``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The attribute :attr:`SimpleTestCase.urls <django.test.SimpleTestCase.urls>`
for specifying URLconf configuration in tests has been deprecated and will be
removed in Django 2.0. Use :func:`@override_settings(ROOT_URLCONF=...)
<django.test.override_settings>` instead.

``prefix`` argument to :func:`~django.conf.urls.i18n.i18n_patterns`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Related to the previous item, the ``prefix`` argument to
:func:`django.conf.urls.i18n.i18n_patterns` has been deprecated. Simply pass a
list of :func:`django.conf.urls.url` instances instead.

Using an incorrect count of unpacked values in the :ttag:`for` template tag
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Using an incorrect count of unpacked values in :ttag:`for` tag will raise an
exception rather than fail silently in Django 2.0.
