Version 98 (modified by Malcolm Tredinnick, 17 years ago) ( diff )

Added a comforting note to the DecimalField SQLite change.

Backwards-incompatible changes

As Django is still in pre-1.0 mode, we haven't yet committed to maintaining backwards compatibility in any APIs. Although we're keeping such changes to a minimum, Django developers should be acutely aware of these changes.

Of course, once we reach 1.0, we'll be strongly committed to backward compatibility.

This page lists all backwards-incompatible changes to Django since the 0.95 release. For changes prior to 0.95, see the OlderBackwardsIncompatibleChanges page.

Table of Contents

Changes made after Django [source:/django/tags/releases/0.95 0.95]:

Changes made after Django [source:/django/tags/releases/0.96 0.96]:

Database constraint names changed

As of [3512], the format of the constraint names Django generates for foreign key references changed slightly. These names are only used sometimes, when it is not possible to put the reference directly on the affected column, so this is not always visible.

The effect of this change is that manage.py reset app_name and similar commands may generate SQL with invalid constraint names and thus generate an error when run against the database (the database server will complain about the constraint not existing). To fix this, you will need to tweak the output of manage.py sqlreset app_name to match the correct constraint names and pass the results to the database server manually.

Backslash escaping changed

As of [3552], the Django database API now escapes backslashes given as query parameters. If you have any database API code that match backslashes, and it was working before (despite the broken escaping), you'll have to change your code to "unescape" the slashes one level.

For example, this used to work:

# Code that matches a single backslash
MyModel.objects.filter(text__contains='\\\\')

But it should be rewritten as this:

# Code that matches a single backslash
MyModel.objects.filter(text__contains='\\')

Removed ENABLE_PSYCO setting

As of [3877], the ENABLE_PSYCO setting no longer exists. If your settings file includes ENABLE_PSYCO, nothing will break per se, but it just won't do anything. If you want to use Psyco with Django, write some custom middleware that activates Psyco.

Enforcing MySQLdb version

As of [4724], Django raises an error if you try to use the MySQL backend with a MySQLdb (MySQL Python module) version earlier than 1.2.1p2. There were significant, production-related bugs in earlier versions, so we have upgraded the minimum requirement.

In [4767], we added a mysql_old backend, which is identical to the mysql backend prior to the change in [4724]. You can use this backend if upgrading the MySQLdb module is not immediately possible. However, the mysql_old backend is deprecated, and we will not continue developing it.

Changed 'spaceless' template tag to remove all spaces

As of [4885], the spaceless template tag removes *all* spaces between HTML tags instead of preserving a single space.

For example, for this template code:

{% spaceless %}
<p>
    <a href="foo/">Foo</a>
</p>
{% endspaceless %}

The old output was this:

<p> <a href="foo/">Foo</a> </p>

The new output is this:

<p><a href="foo/">Foo</a></p>

As always, spaceless only affects space *between* HTML tags, not space within HTML tags or space in plain text.

Renamed localflavor.usa to localflavor.us

As of [4954], localflavor.usa has been renamed localflavor.us. This change was made to match the naming scheme of other local flavors.

Removed LazyDate

The LazyDate helper class was removed in [4985]. Default field values and query arguments can both be callable objects, so instances of LazyDate can be replaced with a reference to a callable that evaluates to the current date (i.e., datetime.now). For example, the following model using LazyDate:

class Article(models.Model):
    title = models.CharField(maxlength=100)
    published = models.DateField(default=LazyDate())

can be redefined as:

from datetime import datetime
class Article(models.Model):
    title = models.CharField(maxlength=100)
    published = models.DateField(default=datetime.now)

Note that the new model definition refers to the name of the datetime.now() function, but doesn't actually call the function. The call to datetime.now() is deferred until the value is actually required (i.e., when the model is saved).

MySQL Introspection Change

In [5042] a small change was made in the mysql backend in how it interpreted CHAR(n) columns in the database. They are now mapped to Django's CharField class, rather than the previous TextField. See ticket #4048 for details.

This will only be apparent if you introspect a database table using 0.96 and again using [5042] or later: you will have slightly different Django models generated if there are any CHAR(n) columns. However, no real code changes should be necessary.

LOGIN_URL is now a setting

In [5072], we moved the LOGIN_URL constant from django.contrib.auth into the settings module. This was part of a broader change to make these URLs (including logout and post-login redirect) configurable. Code that previously read

from django.contrib.auth import LOGIN_URL

should be changed to refer to settings.LOGIN_URL instead.

Test Client login() method changed

The implementation of django.test.Client.login() operated as a wrapper around a series of GET and POST calls accessing a nominated login URL. This approach was fragile, and tightly bound to specific templates and login mechanims.

In [5152], we changed the implementation of the login() method on the test Client. login() now accepts a list of credentials, and exercises these credentials directly on the cookies and Session objects of a site, without accessing or using a login page. This breaks the dependence on specific template formatting, and enables the login mechanism to work with any authentication backend, and any login decorator.

Existing uses of login(), e.g.:

c = Client()
c.login('/path/to/login','myuser','mypassword')

should be modified to read:

c = Client()
c.login(username='myuser', password='mypassword')

The keyword arguments username and password *must* be given explicitly. If an alternate authentication scheme is in use, the credentials required by that scheme can be provided instead of username and password.

Generic relations have moved

In [5172], the various generic relation classes (GenericForeignKey and GenericRelation) have moved into the django.contrib.contenttypes module. This is because they will not work if contenttypes is not an installed app. Making the import path reflect the dependency should help remind people of this.

Code using generic relations should change from saying things like

generic_field = models.GenericRelation(SomeOtherModel)

to using

from django.contrib.contenttypes import generic
...
generic_field = generic.GenericRelation(SomeOtherModel)

No database changes or other model changes are required.

Newforms: clean_data changed to cleaned_data

If you are accessing form data that has been cleaned in newforms, you could previously use the clean_data attribute on the form. In [5237], this was changed to cleaned_data to avoid a name-clash (see [5231] for why the change was necessary).

You will need to do a search-and-replace in your form code and replace clean_data with cleaned_data everywhere.

Renamed FloatField to DecimalField

In [5302], we fixed a slight inconsistency in Django's model field system. Previously, we had a FloatField that had a maximum number of digits and decimal places. However, although it was stored in the database as a fixed precision value, it was stored in Python as a float, so precision was lost due to rounding problems.

We now have a DecimalField class that is the same as the old FloatField, except that it is represented in Python by a Decimal type (and still stored as a fixed precision value in the database). We have also introduced a proper FloatField that is represented as a float in Python and stored as a "double precision" field in the database.

To make your code compatible with these changes, you need to change all occurrences of FloatField in your code to DecimalField. You only need to rename the field type -- all the parameters are the same. So change

class MyModel(models.Model):
    ...
    field_name = models.FloatField(max_digits=10, decimal_places=3)    # old code!

to

class MyModel(models.Model):
    ...
    field_name = models.DecimalField(max_digits=10, decimal_places=3)    # new code!

If you forget to make this change, you will see errors about FloatField not taking a max_digits attribute in __init__, since the new FloatField takes no precision-related arguments.

If you are using MySQL or PostgreSQL, there are no further changes needed. The database column types for DecimalField are the same as for the old FloatField.

If you are using SQLite, you need to force the database to view the appropriate columns as decimal types, rather than floats. To do this, follow this procedure for every application you have that contains a DecimalField. Do this after you have made the change to using DecimalField in your code and updated the Django code.

Warning: Back up your database first! For SQLite, this means making a copy of the single file that stores the database (the name of that file is the DATABASE_NAME in your settings.py file).

For every application using a DecimalField, do the following. We will use applications call some_app and another_app in this example

./manage.py dumpdata --format=xml some_app another_app > data-dump.xml
./manage.py reset some_app another_app
./manage.py loaddata data-dump.xml

Notes:

  1. It is important that you remember to use XML format in the first step of this process. We are exploiting a feature of the XML data dumps that makes porting floats to decimals with SQLite possible.
  2. In the second step you will be asked to confirm that you are prepared to lose the data for the application(s) in question. We restore this data in the third step, of course.
  3. DecimalField is not used in any of the apps shipped with Django prior to this change being made, so you do not need to worry about performing this procedure for any of the standard Django applications.

If something goes wrong in the above process, just copy your backed up database file over the top of the original file and start again.

Note: See TracWiki for help on using the wiki.
Back to Top