2011-03-31 01:34:01 +08:00
|
|
|
============================================
|
|
|
|
Django 1.4 release notes - UNDER DEVELOPMENT
|
|
|
|
============================================
|
|
|
|
|
|
|
|
This page documents release notes for the as-yet-unreleased Django
|
|
|
|
1.4. As such, it's tentative and subject to change. It provides
|
|
|
|
up-to-date information for those who are following trunk.
|
|
|
|
|
|
|
|
Django 1.4 includes various `new features`_ and some minor `backwards
|
|
|
|
incompatible changes`_. There are also some features that have been dropped,
|
|
|
|
which are detailed in :doc:`our deprecation plan </internals/deprecation>`.
|
|
|
|
|
|
|
|
.. _new features: `What's new in Django 1.4`_
|
|
|
|
.. _backwards incompatible changes: backwards-incompatible-changes-1.4_
|
|
|
|
|
|
|
|
What's new in Django 1.4
|
|
|
|
========================
|
|
|
|
|
2011-04-21 05:00:24 +08:00
|
|
|
``SELECT FOR UPDATE`` support
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django 1.4 now includes a :meth:`QuerySet.select_for_update()
|
|
|
|
<django.db.models.query.QuerySet.select_for_update>` method which generates a
|
|
|
|
``SELECT ... FOR UPDATE`` SQL query. This will lock rows until the end of the
|
|
|
|
transaction, meaning that other transactions cannot modify or delete rows
|
|
|
|
matched by a ``FOR UPDATE`` query.
|
|
|
|
|
|
|
|
For more details, see the documentation for
|
|
|
|
:meth:`~django.db.models.query.QuerySet.select_for_update`.
|
|
|
|
|
2011-04-21 08:00:32 +08:00
|
|
|
HTML5
|
|
|
|
~~~~~
|
|
|
|
|
|
|
|
We've switched the admin and other bundled templates to use the HTML5
|
|
|
|
doctype. While Django will be careful in its use of HTML5 features, to maintain
|
|
|
|
compatibility with old browsers, this change means that you can use any HTML5
|
|
|
|
features you need in admin pages without having to lose HTML validity or
|
|
|
|
override the provided templates to change the doctype.
|
|
|
|
|
2011-05-03 18:44:23 +08:00
|
|
|
List filters in admin interface
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Prior to Django 1.4, the Django admin app allowed specifying change list
|
|
|
|
filters by specifying a field lookup (including spanning relations), and
|
|
|
|
not custom filters. This has been rectified with a simple API previously
|
|
|
|
known as "FilterSpec" which was used internally. For more details, see the
|
|
|
|
documentation for :attr:`~django.contrib.admin.ModelAdmin.list_filter`.
|
|
|
|
|
2011-04-29 19:49:59 +08:00
|
|
|
``reverse_lazy``
|
|
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
A lazily evaluated version of :func:`django.core.urlresolvers.reverse` was
|
|
|
|
added to allow using URL reversals before the project's URLConf gets loaded.
|
|
|
|
|
2011-05-03 19:52:42 +08:00
|
|
|
Assignment template tags
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
A new helper function,
|
|
|
|
:ref:`assignment_tag<howto-custom-template-tags-assignment-tags>`, was added to
|
|
|
|
``template.Library`` to ease the creation of template tags that store some
|
|
|
|
data in a specified context variable.
|
|
|
|
|
2011-03-31 01:34:01 +08:00
|
|
|
.. _backwards-incompatible-changes-1.4:
|
|
|
|
|
|
|
|
Backwards incompatible changes in 1.4
|
|
|
|
=====================================
|
2011-03-31 01:35:32 +08:00
|
|
|
|
|
|
|
Compatibility with old signed data
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django 1.3 changed the cryptographic signing mechanisms used in a number of
|
|
|
|
places in Django. While Django 1.3 kept fallbacks that would accept hashes
|
|
|
|
produced by the previous methods, these fallbacks are removed in Django 1.4.
|
|
|
|
|
|
|
|
So, if you upgrade to Django 1.4 directly from 1.2 or earlier, you may
|
|
|
|
lose/invalidate certain pieces of data that have been cryptographically signed
|
|
|
|
using an old method. To avoid this, use Django 1.3 first, for a period of time,
|
|
|
|
to allow the signed data to expire naturally. The affected parts are detailed
|
|
|
|
below, with 1) the consequences of ignoring this advice and 2) the amount of
|
|
|
|
time you need to run Django 1.3 for the data to expire or become irrelevant.
|
|
|
|
|
|
|
|
* contrib.sessions data integrity check
|
|
|
|
|
|
|
|
* consequences: the user will be logged out, and session data will be lost.
|
|
|
|
|
|
|
|
* time period: defined by SESSION_COOKIE_AGE.
|
|
|
|
|
|
|
|
* contrib.auth password reset hash
|
|
|
|
|
|
|
|
* consequences: password reset links from before the upgrade will not work.
|
|
|
|
|
|
|
|
* time period: defined by PASSWORD_RESET_TIMEOUT_DAYS.
|
|
|
|
|
|
|
|
Form related hashes — these are much shorter lifetime, and are relevant only for
|
|
|
|
the short window where a user might fill in a form generated by the pre-upgrade
|
|
|
|
Django instance, and try to submit it to the upgraded Django instance:
|
|
|
|
|
|
|
|
* contrib.comments form security hash
|
|
|
|
|
|
|
|
* consequences: the user will see a validation error "Security hash failed".
|
|
|
|
|
|
|
|
* time period: the amount of time you expect users to take filling out comment
|
|
|
|
forms.
|
|
|
|
|
|
|
|
* FormWizard security hash
|
|
|
|
|
|
|
|
* consequences: the user will see an error about the form having expired,
|
|
|
|
and will be sent back to the first page of the wizard, losing the data
|
|
|
|
they have inputted so far.
|
|
|
|
|
|
|
|
* time period: the amount of time you expect users to take filling out the
|
|
|
|
affected forms.
|
|
|
|
|
|
|
|
* CSRF check
|
|
|
|
|
|
|
|
* Note: This is actually a Django 1.1 fallback, not Django 1.2,
|
|
|
|
and applies only if you are upgrading from 1.1.
|
|
|
|
|
|
|
|
* consequences: the user will see a 403 error with any CSRF protected POST
|
|
|
|
form.
|
|
|
|
|
|
|
|
* time period: the amount of time you expect user to take filling out
|
|
|
|
such forms.
|
2011-04-20 22:41:47 +08:00
|
|
|
|
|
|
|
django.contrib.flatpages
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Starting in the 1.4 release the
|
|
|
|
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` only
|
|
|
|
adds a trailing slash and redirects if the resulting URL refers to an existing
|
|
|
|
flatpage. For example, requesting ``/notaflatpageoravalidurl`` in a previous
|
|
|
|
version would redirect to ``/notaflatpageoravalidurl/``, which would
|
|
|
|
subsequently raise a 404. Requesting ``/notaflatpageoravalidurl`` now will
|
|
|
|
immediately raise a 404. Additionally redirects returned by flatpages are now
|
|
|
|
permanent (301 status code) to match the behaviour of the
|
|
|
|
:class:`~django.middleware.common.CommonMiddleware`.
|
2011-04-29 23:11:17 +08:00
|
|
|
|
|
|
|
`COMMENTS_BANNED_USERS_GROUP` setting
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django's :doc:`comments app </ref/contrib/comments/index>` has historically
|
|
|
|
supported excluding the comments of a special user group but never documented
|
|
|
|
the feature properly and didn't enforce the exclusion in other parts of the
|
|
|
|
app, e.g. the template tags. To fix this problem the code was removed from
|
|
|
|
the feed class.
|
|
|
|
|
|
|
|
If you rely on the feature and want to restore the old behaviour, simply use
|
|
|
|
a custom comment model manager to exclude the user group, e.g.::
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
from django.contrib.comments.managers import CommentManager
|
|
|
|
|
|
|
|
class BanningCommentManager(CommentManager):
|
|
|
|
|
|
|
|
def get_query_set(self):
|
|
|
|
qs = super(BanningCommentManager, self).get_query_set()
|
|
|
|
if getattr(settings, 'COMMENTS_BANNED_USERS_GROUP', None):
|
|
|
|
where = ['user_id NOT IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)']
|
|
|
|
params = [settings.COMMENTS_BANNED_USERS_GROUP]
|
|
|
|
qs = qs.extra(where=where, params=params)
|
|
|
|
return qs
|
|
|
|
|
|
|
|
Save this model manager in your custom comment app (e.g. in
|
|
|
|
``my_comments_app/managers.py``) and add it your
|
|
|
|
:ref:`custom comment app model <custom-comment-app-api>`::
|
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.contrib.comments.models import Comment
|
|
|
|
|
|
|
|
from my_comments_app.managers import BanningCommentManager
|
|
|
|
|
|
|
|
class CommentWithTitle(Comment):
|
|
|
|
title = models.CharField(max_length=300)
|
|
|
|
|
|
|
|
objects = BanningCommentManager()
|
|
|
|
|
|
|
|
For more details see the docs about
|
|
|
|
:doc:`customizing the comments framework </ref/contrib/comments/custom>`.
|
2011-05-06 04:49:26 +08:00
|
|
|
|
|
|
|
`IGNORABLE_404_STARTS` and `IGNORABLE_404_ENDS` settings
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Django can report 404 errors: see :doc:`/howto/error-reporting`.
|
|
|
|
Until Django 1.3, it was possible to exclude some URLs from the reporting
|
|
|
|
by adding prefixes to :setting:`IGNORABLE_404_STARTS` and suffixes to
|
|
|
|
:setting:`IGNORABLE_404_ENDS`.
|
|
|
|
|
|
|
|
In Django 1.4, these two settings are superseded by
|
|
|
|
:setting:`IGNORABLE_404_URLS`, which is a list of compiled regular expressions.
|
|
|
|
Django won't send an email for 404 errors on URLs that match any of them.
|
|
|
|
|
|
|
|
Furthermore, the previous settings had some rather arbitrary default values::
|
|
|
|
|
|
|
|
IGNORABLE_404_STARTS = ('/cgi-bin/', '/_vti_bin', '/_vti_inf')
|
|
|
|
IGNORABLE_404_ENDS = ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi',
|
|
|
|
'favicon.ico', '.php')
|
|
|
|
|
|
|
|
It's not Django's role to decide if your website has a legacy ``/cgi-bin/``
|
|
|
|
section or a ``favicon.ico``. As a consequence, the default values of
|
|
|
|
:setting:`IGNORABLE_404_URLS`, :setting:`IGNORABLE_404_STARTS` and
|
|
|
|
:setting:`IGNORABLE_404_ENDS` are all now empty.
|
|
|
|
|
|
|
|
If you have customized :setting:`IGNORABLE_404_STARTS` or
|
|
|
|
:setting:`IGNORABLE_404_ENDS`, or if you want to keep the old default value,
|
|
|
|
you should add the following lines in your settings file::
|
|
|
|
|
|
|
|
import re
|
|
|
|
IGNORABLE_404_URLS = (
|
|
|
|
# for each <prefix> in IGNORABLE_404_STARTS
|
|
|
|
re.compile(r'^<prefix>'),
|
|
|
|
# for each <suffix> in IGNORABLE_404_ENDS
|
|
|
|
re.compile(r'<suffix>$'),
|
|
|
|
)
|
|
|
|
|
|
|
|
Don't forget to escape characters that have a special meaning in a regular
|
|
|
|
expression.
|