Context Navigation

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.

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:

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

fromdjango.contrib.authimport 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.

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.

Test client removed special casing for file uploads

Before [5465], Django's client in the testing infrastructure had special casing for file uploads that matched the implementation of the FileField datatype, making it simpler to use for this case. To allow for different methods of uploading files (e.g. newforms and oldforms), this has been removed--you will have to update your tests if you depended on this behaviour (look at the HTML source to work out what the field names for posted data should be).

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

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 called some_app and another_app in this example

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.

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.

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.

Urlpatterns now cached

In [5516], a speed improvement was made for reverse URL lookups, particularly. Part of this involved caching information that was unlikely to change: the urlpatterns() contents.

If you were somehow relying on the fact that you could change your urls.py files and not have to restart Django, you can no longer do that. Edits require a restart.

Unicode merge

In [5609], the UnicodeBranch was merged into trunk. For any installations using ASCII data, this is fully backwards compatible.

If you were using non-ASCII data, Django would have behaved unreliably in some cases previously and so backwards-compatibility was neither completely possible nor desirable. However, some people may have been able to get by with non-ASCII data successfully. They might now experience some different errors to previously. Porting code to work correctly with non-ASCII data is fairly simple. Follow ​this checklist for fastest results.

Changed __init__() parameters in syndication framework's Feed class

In [5654], we changed the Feed class' __init__() method to take an HttpRequest object as its second parameter, instead of the feed's URL. This allows the syndication framework to work without requiring the sites framework.

This only affects people who have subclassed Feed and overridden the __init__() method, and people who have called Feed.__init__() directly from their own code. Feed.__init__() had not been documented.

PO files must be UTF-8 encoded

In [5708] we added the ability to use non-ASCII strings as input to the translation framework. This was a frequently requested feature by developers whose original strings were not in English. A consequence of this change is that we have to specify the encoding of the PO files (the files used by translators to create translations). Following common practice in other projects, we have chosen UTF-8 as the encoding.

This change only affects third-party developers who are using Django's make-messages.py script to extract their strings for their own PO files. The PO files will need to be saved and edited as UTF-8 files and the charset set correctly in the header of the file. All of Django's core translation files already satisfy this requirement.

Note that existing code and message catalogs will not break even if you update your code to [5708] or later. This change only takes effect the next time you run make-messages.py.

Added interactive argument to run_tests

In [5752] the parameter interactive was added to the run_tests method. This parameter allows tests to be added to automated build scripts where interactive questions (such as being asked if it is ok to delete an existing test database) cannot be asked.

If you are using the default Django test runner, no change is required.

However, if you have defined a custom test runner, you must be able to accept (and handle appropriately) the interactive argument to the test runner. For most test runners, the only change required will be to change the call to create_test_db to use the keyword argument autoclobber=not interactive.

Changed format for first argument to run_tests

In [5769], the first argument to run_tests was changed to allow end-users to invoke individual tests, rather than requiring that entire applications be tested.

This change has no effect on most end users. However, it does require a significant change to the prototype of run_test, which will be backwards incompatible for anyone with a customized test runner. Previously, the first argument to run_tests was a list of application modules. These modules would then be searched for test cases. After [5769], the first argument to run_tests is a list of test labels. Whereas run_tests was previously given a list of already-loaded applications, it is now the responsibility of the test runner to load the appropriate applications. Anyone with a customized test runner will need to incorporate the appropriate calls to get_app() as part of their test runner.

Minor change to newforms arguments and data dictionary handling

In [5819], FileField and ImageField were added to newforms. Implementing these fields required some subtle changes to the way data binding occurs in newforms.

This change will have no effect on most end users. The simple cases for binding forms do not change. However:

The second argument to a form instance is now taken by file data. As a result, if you implicitly relied upon the order of the keyword arguments auto_id, prefix and initial when instantiating forms, your forms will no longer interpret these options correctly. To overcome this problem, explicitly name these keyword arguments - for example, use:

f = ContactForm(data, auto_id=True)

rather than:

f = ContactForm(data, True)

A files argument was added to the prototype for value_from_datadict() to allow for the processing of file data. If you have written any custom widgets that provide their own data dictionary handling, you will need to modify those widgets to accomodate the new argument. If your custom widget has no need to handle file data, all you will need to do is change the method definition from:

def value_from_datadict(self, data, name):

to:

def value_from_datadict(self, data, files, name):

Changes to management.py commands

In [5898], we refactored management.py. This was partially to clean up a 1700-line file, but also to allow user applications to register commands for use in management.py.

As a result, any calls to management services in your code will need to be adjusted. For example, if you have some test code that calls flush and load_data:

Refactored database backends

In a series of commits from [5949] to [5982], we refactored the database backends (the code in django.db.backends) to remove quite a bit of duplication, make it easier to maintain and extend, and to lay the groundwork for advanced features such as database connection pooling.

As a result, almost *all* of the backend-level functions have been renamed and/or relocated. None of these were documented, but you'll need to change your code if you're using any of these functions:

Old name/location

New name/location

django.db.backend.get_autoinc_sql

django.db.connection.ops.autoinc_sql

django.db.backend.get_date_extract_sql

django.db.connection.ops.date_extract_sql

django.db.backend.get_date_trunc_sql

django.db.connection.ops.date_trunc_sql

django.db.backend.get_datetime_cast_sql

django.db.connection.ops.datetime_cast_sql

django.db.backend.get_deferrable_sql

django.db.connection.ops.deferrable_sql

django.db.backend.get_drop_foreignkey_sql

django.db.connection.ops.drop_foreignkey_sql

django.db.backend.get_fulltext_search_sql

django.db.connection.ops.fulltext_search_sql

django.db.backend.get_last_insert_id

django.db.connection.ops.last_insert_id

django.db.backend.get_limit_offset_sql

django.db.connection.ops.limit_offset_sql

django.db.backend.get_max_name_length

django.db.connection.ops.max_name_length

django.db.backend.get_pk_default_value

django.db.connection.ops.pk_default_value

django.db.backend.get_random_function_sql

django.db.connection.ops.random_function_sql

django.db.backend.get_sql_flush

django.db.connection.ops.sql_flush

django.db.backend.get_sql_sequence_reset

django.db.connection.ops.sequence_reset_sql

django.db.backend.get_start_transaction_sql

django.db.connection.ops.start_transaction_sql

django.db.backend.get_tablespace_sql

django.db.connection.ops.tablespace_sql

django.db.backend.quote_name

django.db.connection.ops.quote_name

django.db.backend.get_query_set_class

django.db.connection.ops.query_set_class

django.db.backend.get_field_cast_sql

django.db.connection.ops.field_cast_sql

django.db.backend.get_drop_sequence

django.db.connection.ops.drop_sequence_sql

django.db.backend.OPERATOR_MAPPING

django.db.connection.operators

django.db.backend.allows_group_by_ordinal

django.db.connection.features.allows_group_by_ordinal

django.db.backend.allows_unique_and_pk

django.db.connection.features.allows_unique_and_pk

django.db.backend.autoindexes_primary_keys

django.db.connection.features.autoindexes_primary_keys

django.db.backend.needs_datetime_string_cast

django.db.connection.features.needs_datetime_string_cast

django.db.backend.needs_upper_for_iops

django.db.connection.features.needs_upper_for_iops

django.db.backend.supports_constraints

django.db.connection.features.supports_constraints

django.db.backend.supports_tablespaces

django.db.connection.features.supports_tablespaces

django.db.backend.uses_case_insensitive_names

django.db.connection.features.uses_case_insensitive_names

django.db.backend.uses_custom_queryset

django.db.connection.features.uses_custom_queryset

archive_year generic view no longer performs an order_by() on the passed queryset

In [6057], archive_year was changed NOT to perform an order_by() on the passed queryset. This is for consistancy with the other date-based generic views.

Update your code by performing an explicit order_by() on the QuerySet you pass to archive_year or add an ordering option to your model's class Meta.

django-admin.py and manage.py now require subcommands to precede options

In [6075], django-admin.py and manage.py were changed so that any options (e.g., --settings) must be specified *after* the subcommand (e.g., runserver).

This used to be accepted:
django-admin.py --settings=foo.bar runserver

Now, options must come after the subcommand:
django-admin.py runserver --settings=foo.bar

django.views.i18n.set_language requires a POST request

In [6177], the set_language() view was changed to only change the caller's locale if called as a POST request. Previously, a GET request was used. The old behaviour meant that state (the locale used to display the site) could be changed by a GET request, which is against the HTTP specification's recommendations.

Code calling this view must ensure that a POST request is now made, instead of a GET. This means you can no longer use a link to access the view, but must use a form submission of some kind (e.g. a button).

django.http.HttpResponse now has case-insensitive headers

In a number of changes starting with [6212], HttpResponse headers were made case-insensitive.

As a side-effect, could break code that accesses response.headers directly, and specifically broke the idiom if header in response.headers:.

So response.headers has been renamed to response._headers, and HttpResponse now supports containment checking directly. You should now use if header in response instead of if header in response.headers.

Template tag loading respects dotted notation

In [6289], template tag loading was altered to respect dotted paths, just like Python imports. So

{% load foo.bar %}

will now look for a file foo/bar.py under one of your templatetag directories.

Previously, anything before the final dot was ignored. If you were using this for any decorative purpose (at least one package was, it turns out), you have to remove any unwanted prefix.

If you were previously relying on _() always being present, you should now explicitly import ugettext or ugettext_lazy or even gettext, if appropriate, and alias it to _ yourself:

fromdjango.utils.translationimport ugettext as _

django.newforms.forms.SortedDictFromList class removed

In [6668], the SortedDictFromList class was removed. Due to django.utils.datastructures.SortedDict gaining the ability to be instantiated with a sequence of tuples (#5744), SortedDictFromList was no longer needed. Two things need to be done to fix your code:

Use django.utils.datastructures.SortedDict wherever you were using django.newforms.forms.SortedDictFromList.

Since SortedDict's copy method doesn't return a deepcopy as SortedDictFromList's copy method did, you will need to update your code if you were relying on SortedDictFromList.copy to return a deepcopy. Do this by using copy.deepcopy instead of SortedDict's copy method.

Automatic HTML escaping (henceforth auto-escaping) affects any variables in templates. It is only applied to variables and not to template tags.

{{ a_variable }} -- This will be auto-escaped.
{{ variable|filter1|filter1 }} -- so will this
{% a_template_tag %} -- This will not be; it's a tag

Also note that the escape filter's behaviour has changed slightly (it is only applied once and only as the last thing done to the output) and new filters force_escape and safe have been introduced if you need them.

If you never intentionally insert raw HTML into your context variables, and if all your templates are supposed to output HTML, no changes will be needed.

If you have any variables in your templates that do insert raw HTML output and you do not want this output automatically escaped, you will need to make some changes. There are two approaches here, the first one being the easiest (but not the safest) and can act as a temporary step whilst you do the more detailed second step.

If one template extends from another template, the auto-escaping behaviour from the root template (the one in the {% extends ... %} tag) will be inherited. So you only need to add these tags to your root templates.

This is also the recommended approach for templates that produce, say, email messages or other non-HTML output. The autoescape template tag exists for this reason.

Finally, change all calls to the 'escape' function to use 'force_escape' instead.

The drawback of this method in templates that are destined for HTML output is that you receive none of the benefits of auto-escaping.

More detailed porting to take advantage of auto-escaping: There are two approaches to inserting raw HTML via variables into templates. One option is to pass the variable content through the safe filter. This tells the renderer not to auto-escape the contents:

{{ variable_with_html|safe }} -- will not be auto-escaped.

The second and probably more robust way is to use mark_safe() where appropriate (see ​the documentation for details) and go through each of your custom filters attaching is_safe and needs_autoescape attributes where necessary (again, the details are in the above documentation).

Have a look at Django's default filters (in django/template/defaultfilters.py) for examples of how mixed filters (those which behave differently depending upon whether auto-escaping is in effect or not) can be written.

The attributes on filter functions and the new escape behaviour mean that you can write templates and filters that will operate correctly in both auto-escaping and non-auto-escaping environments, so you're not forcing your decision onto users of your filters, if you distribute the code.

Removed unused session backend functions

In [6796] a couple of session backend functions that are no longer needed were removed. In the unlikely event your code was using get_new_session_key() or get_new_session_object(), you will need to switch to using SessionBase._get_new_session_key().

Settings exception types changed

In [6832] we changed the possible exceptions raised when initializing Django's settings in order not to interfere with Python's help() function. If there is a problem such as not being able to find the settings module (via the DJANGO_SETTINGS_MODULE environment variable, for example), an ImportError is now raised (previously it was EnvironmentError). If you try to reconfigure settings after having already used them, a RuntimeError is raised (rather than the previous EnvironmentError). See #5743 for the details of this change.

Generic views' empty defaults

In [6833] the allow_empty parameter to the archive_index() and object_list() generic views were changed to be True by default. So viewing a list of objects that is empty will not raise a 404 HTTP error. Things like date-based views still raise a 404 when there is nothing to view (by default), since viewing a non-existent date is usually going to be an error. See #685 for details.

MultipleObjectsReturned exception instead of AssertionError

In [6838], QuerySet.get() was changed to raise a MultipleObjectsReturned exception rather than an assertion error when multiple objects are returned.

Before:

try:
Model.objects.get(...)exceptAssertionError:...

After:

try:
Model.objects.get(...)except Model.MultipleObjectsReturned:...

Change to APPEND_SLASH behaviour

Prior to [6852], if a URL didn't end in a slash or have a period in the final component of it's path, and APPEND_SLASH was True, Django would redirect to the same URL, but with a slash appended to the end.

Now (from [6852] onwards), Django checks to see if the pattern without the trailing slash would be matched by something in your URL patterns. If so, no redirection takes place, because it is assumed you deliberately wanted to catch that pattern.

For most people, this won't require any changes. Some people, though, have URL patterns that look like this:

r'/some_prefix/(.*)$'

Previously, those patterns would have been redirected to have a trailing slash. If you always want a slash on such URLs, rewrite the pattern as

r'/some_prefix/(.*/)$'

Now /some_prefix/foo will not match the pattern and will be redirected to /some_prefix/foo/, which will match. Your view function will be passed foo/, just as it was prior to [6852].

ModelForm's constructor now matches Form's

instance was moved from the first argument in ModelForm's __init__ method to the last. Also, ModelForm will instantiate a new model object if you don't give it an instance. The model it generates is specified by the ModelForm's inner Meta classes model attribute. See #6162 for details.

Raise errors if extends is not the first tag of a template

In [7082] we removed the possibility of putting extends below other tags (in [7089]). You may still put it below comment tags or whitespace. Otherwise it will raise a TemplateSyntaxError. This is not technically a backward incompatible change because documentation has always specified that ​extends tags should be placed first in your templates, but it may break your code if you haven't followed those instructions.

Change es_AR to es-ar in LANGUAGES

In [7091] we fixed a bug that was inadvertently introduced recently with regards to parsing language preferences. The LANGUAGES list in the configuration file should use a hyphen to separate the locale main name and the variant (if any).

The only slight consequence here is that the Argentinean Spanish was incorrectly specified as es_AR. If you are using Django's default language list, there is no change required, since the central list has been updated and specifying es-ar as the preference in your browser will still work. However, if you have created a custom LANGUAGES list in your settings file, overriding the list in global_settings, you will need to change "es_AR" to read "es-ar", otherwise your Argentinean Spanish readers will see English text, not Spanish.

Changed Field.get_internal_type() default

If you were subclassing an existing model field and were relying on the fact that the Field.get_internal_type() method would return your class name by default, you will need to alter your code to explicitly say that (i.e. to return the string you want). It seemed that most subclassing of existing fields (even in Django core) were using the parent's column type, so we've now set things up to exploit that. Thus, inheriting from a CharField results in get_internal_type() returning CharField, etc.

Changed decorators to inherit attributes of the function they wrap

If you were using one of Django's decorators and relying on decorated functions/methods to have the name (__name__), docstring (__doc__), or attributes (__dict__) of the decorator, then you need to change your code to work off the name, docstring, or attributes of the decorated function instead. If you are using Python 2.3, you don't need to worry about the changing of the decorated function's name since Python 2.3 does not support assignment to __name__.

Removed ado_mssql

The unmaintained ado_mssql backend was removed in [7364]. Since external database backends can be used with Django, people wishing to contribute to or utilise Django support on Microsoft's SQL Server should have a look at external projects such as:

Tightened up ForeignKey assignment

[7574] tightened up restrictions on assigning objects to ForeignKey and OneToOne fields (i.e. assignments of the form book.author = someinstance).

Specifically, Django will now:

Raise a ValueError if you try to assign the wrong type of object. Previously things like book.author = Vegetable(...) worked, which was insane.

Raise a ValueError if you try to assign None to a field not specified with null=True.

Cache the set value at set time instead of just at lookup time. This avoids race conditions when saving related objects along with their parents and was the original impetus for the change (see #6886).

Removed OrderingField

In [7794], a model field that had no use was removed (OrderingField). It was introduced in the magic-removal branch to support a feature that was never completed, so the code isn't useful in Django any longer.

Exact Comparisons Respect Case In MySQL

This change is no longer applicable. See below for details on when it was changed back.

The documented behaviour of the __exact comparison in Django's ORM is that it is case-sensitive. For case-insensitive searches, there is __iexact. On some MySQL installations (which includes most default installations), __exact was using case-insensitive matching. This was changed in [7798] so that using __exact will respect the case of the argument, bringing it into line with all the other database backends.

BooleanFields in newforms enforce "required"

In [7799], a bug was fixed that meant required=True is now enforced by the newforms.BooleanField. In this case, "required" means "must be checked" (i.e. must be True). This has been documented for quite a while, but was inadvertently not enforced by the validation code.

Since required=True is the default behaviour for all form fields, if your code does not set required=False on a BooleanField and you do not require it to be checked in the HTML form, you will need to change your form definition.

Default User ordering removed

Since the django.contrib.auth.models.User class frequently has a lot of rows in the database and is queried often, we have removed the default ordering on this class in [7806]. If your code requires users to be ordered by their name, you will need to manually specify order_by('name') in your querysets.

Note that the admin interface will still behave the same as prior to this change, since it automatically orders the users by their name, just as before. So no change will be noticable there.

Uploaded file changes

[7814] introduced changes to the way Django handles uploaded files. Most of the changes are in the form of added flexibility and performance (for details, see the ​upload handling documentation).

However, as part of the change, the representation of uploaded files has changed. Previous, uploaded files -- that is, entries in request.FILES -- were represented by simple dictionaries with a few well-known keys. Uploaded files are now represented by an ​UploadedFile object, and thus the file's information is accessible through object attributes. Thus, given f = request.FILES['some_field_name']:

Deprecated

Replacement

f['content']

f.read()

f['filename']

f.name

f['content-type']

f.content_type

The old dictionary-style key access is still supported, but will raise a DeprecationWarning.

[7859] further cleaned up and clarified this interface. It unfortunatly had to deprecate a couple of things added in [7814]:

Deprecated

Replacement

f.file_name

f.name

f.file_size

f.size

f.chunk()

f.chunks() (note the plural)

The old attributes will still work, but will issue deprecation warnings.

Finally, [7859] removed the django.newforms.fields.UploadedFile class, unifying the use of django.core.files.uploadedfile.UploadedFile everywhere in Django. This means a few API changes when using a form with a FileField.

Deprecated

Replacement

form.cleaned_data['file_field'].filename

form.cleaned_data['file_field'].name

form.cleaned_data['file_field'].data

form.cleaned_data['file_field'].read()

Translation tools now part of django-admin.py

In [7844] the tools to extract strings for translations (formerly make-messages.py) and compile the PO files (formerly compile-messages.py) were moved into django-admin.py. The old executables still exist, but raise errors and point the caller towards the correct command to run (both of these files are designed to be run from the command line, not as part of other programs).

Old command

New

make-messages.py -l xx

django-admin.py makemessages -l xx

compile-messages.py -l xx

django-admin.py compilemessages -l xx

The options accepted by the new form are the same as the options accepted by the old commands, only the calling convention has changed (this reduced the number of executables Django has to install).

MySQL_old backend removed

In [7949] we removed the mysql_old backend. It was only available for backwards compatibility with a version of MySQLdb that was in popular use in some ISPs at the time. Since MySQLdb-1.2.1p2 was released over 2 years ago and that version, or anything later, works with the mysql backend, we have now removed this formerly deprecated backend.

Note that, in this above URLconf example, we're dealing with the object django.contrib.admin.site. This is an instance of django.contrib.admin.AdminSite, which is a class that lets you specify admin-site functionality. The object django.contrib.admin.site is a default AdminSite instance that is created for you automatically, but you can also create other instances as you see fit.

We use the admin.autodiscover() call above to force the import of the admin.py module of each INSTALLED_APPS entry. This won't be needed if you use your own AdminSite instance since you will likely be importing those modules explicily in a project-level admin.py. This was added in [7872].

Previously, there was one "global" version of the admin site, which used all models that contained a class Admin. This new scheme allows for much more fine-grained control over your admin sites, allowing you to have multiple admin sites in the same Django instance.

Moved inner-model class Admin to ModelAdmin classes

The syntax to define your models in the admin has changed slightly. It is no longer in your model and is instead in an application level admin.py module. Here is a quick example showing you the change:

If your old inner admin class defined options that controlled the behavior of the admin they have moved to class level in a ModelAdmin class. All options are the same with the exception of the ones noted in this section below.

Changed Admin.manager option to more flexible hook

The manager option to class Admin no longer exists. This option was undocumented, but we're mentioning the change here in case you used it. In favor of this option, a ModelAdmin class may now define a queryset method:

classBookAdmin(admin.ModelAdmin):defqueryset(self, request):"""
Filter based on the current user.
"""returnself.model._default_manager.filter(user=request.user)

Changed prepopulate_from to be defined in the Admin class, not database field classes

The prepopulate_from option to database fields no longer exists. It's been discontinued in favor of the new prepopulated_fields option in a ModelAdmin. The new prepopulated_fields option, if given, should be a dictionary mapping field names to lists/tuples of field names. This change was made in an effort to remove admin-specific options from the model itself. Here's an example comparing old syntax and new syntax:

Moved admin doc views into django.contrib.admindocs

The documentation views for the Django admin site were moved into a new package, django.contrib.admindocs.

The admin docs, which aren't documented very well, were located at docs/ in the admin site. They're also linked-to by the "Documentation" link in the upper right of default admin templates.

Because we've moved the doc views, you now have to activate admin docs explicitly. Do this by adding the following line to your URLconf:

(r'^admin/doc/', include('django.contrib.admindocs.urls')),

You have to add this line before r'^admin/(.*)' otherwise it won't work.

Renamed 'fields' to 'fieldsets', and changed type of 'classes' value

'Fields' is used to order and group fields in the change form layout.
It is still available in the new admin, but it accepts only a list of fields.
In case one uses fieldsets to organize the fields, one needs to use 'fieldsets' instead.
Also, if 'classes' is specified in a field specification, then the type of its value needs to be changed from a string to a tuple of strings when migrating to the new 'fieldsets' specification.

Before you would define an edit_inline database field option and give it the value of the type of inline you wanted, either models.TABULAR or models.STACKED. This is now done with classes and gives you much more flexibility over the options of a specific inline. See ​the inlines documentation to learn more.

Refactored inner Admin js option to media definitions

In [5926] a new method of dealing with media definitions was added. It is now
much more flexible and allows media on more than just a ModelAdmin
classes.

One very subtle thing to note is previously with trunk the documentation stated:

If you use relative URLs — URLs that don’t start with http:// or / — then the admin site will automatically prefix these links with settings.ADMIN_MEDIA_PREFIX.

Which is still partially true with newforms-admin, but now when using relative URLs settings.MEDIA_URL is prepended and notsettings.ADMIN_MEDIA_PREFIX. If you are still looking for the old behavior you can accomplish it by doing the following:

Moved newforms to forms

In [7971] Django's newforms library was finally renamed to just plain old forms. Imports of django.newforms will still work but will throw a DeprecationWarning. Deeper imports throw ImportErrors. In general, you'll just need to change from django import newforms as forms to from django import forms.

django.oldforms is still available, but really you shouldn't be using it.

Changed the way URL paths are determined

A long-awaited change was made in [8015] to the way Django works with HTTP URL
strings. Web servers separate request URLs into two pieces, the SCRIPT_NAME
and the PATH_INFO (there is also the QUERY_STRING for query parameters, but
that is not relevant here). Prior to this change, Django was not using the
SCRIPT_NAME at all, which caused a number of problems, including some
portability issues.

The main goal of this change is to make it possible to move a Django project
from being served under, say, URLs of the form /mysite/* to
/my_other_site/* without needing any changes in the URLConf file. The
prefix (/mysite/ and /my_other_site/) is the SCRIPT_NAME portion and
Django only really needs to act on the PATH_INFO portion (the remainder of
the URL).

If your Django project handles all the URLs under '/', you shouldn't have to
make any changes in most cases. In all other cases, some alterations will be
required. This change will have different effects for different web server
setups. In all cases, you should remove the SCRIPT_NAME portion of
the URLs from your URLConf file (they currently need to be included).

mod_python

If you are using mod_python and change nothing (not even URLConf), your code
will still work and will be as non-portable as before. You may wish to leave
things this way.

However, if you wish to take advantage of the portability improvements, remove
the script prefix from URLConf and set the prefix using the django.root
option in mod_python's configuration. A configuration section that used to look
like this:

At the same time, you would edit your URLConf file to remove "/mysite" from
the front of all the URLs.

Apache + fastcgi

If you configure your system using either of the Apache and fastcgi methods
described in Django's fastcgi documentation, all you need to do is
remove the script prefix from the URL patterns in your URLConf.

lighttpd + fastcgi (and others)

Due to the way lighttpd is configured to work with fastcgi, it isn't possible
to automatically construct the right script name value. This will be a problem
is you are using the {% url %} template tag, or anything else that does
reverse URL construction. To overcome this problem, you can use the
FORCE_SCRIPT_NAME Django setting to force the value to whatever you want.

If you're using the basic lighttpd configuration from our site, you'll want:

FORCE_SCRIPT_NAME="/"

This is a bit of a hacky solution, since it requires changing the project
settings every time you change the URL prefix. However, there's nothing that
can be done about that in the general case, since Django is simply not passed
the information it needs to determine the original URL (we want to use a small
number of solutions that works for all web servers, rather than have to include
25 special cases for each webserver and installation possibility).

intfield__in=[''] filter lookups no longer work

Before [8131], MyModel.objects.filter(intfield__in=['']) would return an empty QuerySet, where intfield represents an IntegerField or similar on MyModel. For example, if you had been unpacking a comma-separated list of IDs into a lookup such as:

then your lookup will fail if author_ids is an empty string, as of [8131].

DecimalField conversion tightened

In [8143], the conversion between values in model attributes and values to be inserted into the database was changed internally. A side-effect of this is that Django will raise an error if you try to store a floating point value in a DecimalField. There is no reliable way to convert between a float and a decimal. So you must either store a python decimal value in the model attribute or a string (which will then be converted to a decimal).

Password reset system changed to improve security and usability

In [8162], the password reset views and templates were overhauled. If you have were using the existing views with a customised PasswordResetForm, or with any customised templates (such as the password reset email, or any of the related forms), then you will probably have to update your code (note that these forms/templates had already been updated recently to use newforms). If you manually included the URLs for these views into your project (which is currently the only way to get them), you will need to update -- see the URLs in ​django.contrib.auth.urls

The new system has much better security (#7723 is fixed). It does not reset the password, but sends an emails to the user with a link to click on. It also has much better usability -- the user is then prompted to enter their own password, rather than given a random one (which many users often forget to change). The link for resetting the password will expire as soon as it is used, or after a timeout -- default 3 days.

The edit_inline_type argument for ForeignKey fields was removed, use ​InlineModelAdmin instead.

The QOperator, QNot, QAnd and QOr classes were removed, use the ​Q class instead.

The maxlength argument for model fields was removed, use max_length instead.

Removed dictionary access to request object

In [8202], removed dictionary access to request object to avoid its attributes from being overridden in templates by GET and POST data. Instead, you should use request.REQUEST for the same functionality:

request[key] -> request.REQUEST[key]

key in request -> key in request.REQUEST

request.has_key(key) -> request.REQUEST.has_key(key)

url tag now allows NoReverseMatch exceptions to propagate

Previously NoReverseMatch exceptions were silenced in the {% url %} tag. This is very rarely useful, and usually just produced difficult to find bugs, and so was changed in [8211]. See #8031.

Signal refactoring

[8223] refactored signals and django.dispatch with an eye towards speed. The net result was up to a 90% improvement in the speed of signal handling, but along the way some backwards-incompatible changes were made:

All handlers now must be declared as accepting **kwargs.

Signals are now instances of django.dispatch.Signal instead of anonymous objects.

Connecting, disconnecting, and sending signals are done via methods on the Signal object instead of through module methods in django.dispatch.dispatcher. The module-level methods are deprecated.

The Anonymous and Any sender options no longer exist. You can still receive signals sent by any sender by using sender=None

So, a quick summary of the code changes you'd need to make:

Before

After

def my_handler(sender)

def my_handler(sender, **kwargs)

my_signal = object()

my_signal = django.dispatch.Signal()

dispatcher.connect(my_handler, my_signal)

my_signal.connect(my_handler)

dispatcher.send(my_signal, sender)

my_signal.send(sender)

dispatcher.connect(my_handler, my_signal, sender=Any)

my_signal.connect(my_handler, sender=None)

It may be good practice to create a wrapper for my_handler which accepts **kwargs rather than change the signature of the original function.

Peruvian localflavor change

In 2007, Peru changed from departments to regions for their local district names. In [8230], Django's Peruvian localflavor was updated to reflect this change. Previous uses of the PEDepartmentSelect class (from django.contrib.localflavor.pe.forms) should be changed to use PERegionSelect.

New default form widgets in admin

In [8240], to provide better default stylings in the admin interface, the admin class provides its own default form widgets for rendering of model fields. If you were specifying a particular widget for a custom model field that subclasses one of Django's internal fields, you will need to possibly override the ModelAdmin.formfield_for_dbfield() method.

Removed several more deprecated features for 1.0

Support for representing files as strings was removed. Use django.core.files.base.ContentFile instead.

Support for representing uploaded files as dictionaries was removed. Use django.core.files.uploadedfile.SimpleUploadedFile instead.

The filename, file_name, file_size, and chuck properties of UploadedFile were removed. Use the name, name, size, and chunks properties instead, respectively.

The get_FIELD_filename, get_FIELD_url, get_FIELD_size, and save_FIELD_file methods for Models with FileField fields were removed. Instead, use the path, url, and size attributes and save method on the field itself, respectively.

The get_FIELD_width and get_FIELD_height methods for Models with ImageField fields were removed. Use the width and height attributes on the field itself instead.

The dispatcher connect, disconnect, send, and sendExact functions were removed. Use the signal object's own connect, disconnect, send, and send methods instead, respectively.

The form_for_model and form_for_instance functions were removed. Use a ModelForm subclass instead.

Support for importing django.newforms was removed. Use django.forms instead.

Support for importing django.utils.images was removed. Use django.core.files.images instead.

Support for the follow argument in the create_object and update_object generic views was removed. Use the django.forms package and the new form_class argument instead.

Refactored the Creation and Introspection modules of the database backends

In [8296], the creation and introspection modules of the database backends received a major refactoring. This refactoring introduced a consistent class-based interface to the database backend, and isolated SQL and database-specific code behind the relevant database backends. The refactoring also removed several DatabaseFeature entries in favor of subclassing methods on the creation interface.

Most users will not be affected by this change. However, any user that is manually calling features of the creation and/or introspection modules of the database will need to modify the way they access those modules:

The creation module, previously provided using django.db.get_creation_module(), is now available on the database connection as the attribute connection.creation.

The introspection module, previously provided using django.db.get_introspection_module() is now available on the database connection as the attribute connection.introspection.

The DB shell, previously accessed using django.db.runshell() is now available on the database connection as connection.client.runshell().

Users that have written custom test runners will also be affected; the create_test_db() and destroy_test_db() helper methods (plus a few other methods utilized by these two) have been moved into the database backend as part of the creation interface. You can access these methods using connection.creation.create_test_db() and connection.creation.destroy_test_db()

Lastly, any user that is maintaining an external database backend will need to update their code to use the new interface. The new class-based approach should make backend development much easier, as common behavior can be inherited from the base classes in django.db.backends; only database-specific behavior should require implementation.

Restored earlier exact matching for MySQL

For MySQL users only: Due to a number of unintended side-effects and after carefully considering the alternatives, the changes from [7798] were reverted in [8319]. Thus, __exact filters in MySQL now use the database table's native collation setting to determine whether the match is case-sensitive or case-insensitive.

Added parameter to session backend save() method

Custom session backend writers should add a must_create parameter to the save() methods of their backends after [8340]. This parameter is False by default, but, when True indicates that the save() method should ensure to create a new session object with the given key or else raise a django.contrib.session.backend.base.CreateError exception if an object already exists with that key.

Clear session at logout

In [8343] the django.contrib.auth.logout() function was changed to automatically clear all the session data at logout. Thus, a session ends at logout, and subsequently it is as if the user was visting the site for the first time.

If you wish to put information into the session that is available to the user after they have called your "logout" view, you should store that information in the request.session objects after calling django.contrib.auth.logout().

Polish localflavor changes

In [8345] the names of some of the classes in the Polish localflavor were changed. The new names correspond more closely to the official terms for the fields they represent.

Old name

New name

PLNationalIdentificationNumberField

PLPESELField

PLTaxNumberField

PLNIPField

PLNationalBusinessRegisterField

PLREGONField

PLVoivodeshipSelect

PLProvinceSelect

PLAdministrativeUnitSelect

PLCountiesSelect

Removed validate methods for Model and Model field classes

In [8348], support for the experimental, unsupported model validation was removed. The intention is to replace this with a more complete version of model validation after version 1.0 is released (see #6845).

Specifically, django.db.models.base.Model.validate(), django.db.models.fields.Field.validate(), and django.db.models.fields.Field.validate_full() were removed, along with a few model fields' validate methods.

Corrected MultiValueDict.iteritems to return items rather than lists

In [8399], MultiValueDict.iteritems was changed to return the last value given. Previously, it returned the list as in MultiValueDict.getlist(). Code depending on the old iteritems returning the list should be changed to use MultiValueDict.iterkeys and MultiValueDict.getlist().

Corrected results returned by timesince template filters

Previous to [8535], if an optional argument was used with the timesince filter to specify a baseline date for comparison, the results returned by the timesince filter would act the same as the timeuntil filter. For example, {{ tomorrow|timesince:today }} would return "1 day", rather than "0 minutes".

The documentation for the template tag has always been correct; [8535] corrects the implementation to match the documentation. However, since it is possible that users may be relying upon the incorrect behaviour, it could pose problems for backwards compatibility.

This change was also present from [8481]-[8482]; however, it was temporarily reverted in [8483] while a design issue was resolved.

Removed django-admin adminindex command

[8548] removed the django-admin adminindex command; the changes merged in newforms-admin mean that a custom index template or even a custom AdminSite.index method are a better approach.

Replaced django.contrib.comments

[8557] replaced django.contrib.comments with a modern system that's actually documented. It's also quite different from the old undocumented system; anyone who was using it should read the ​upgrading guide.

Fixed timesince filter to handle timezone-aware times

In [8579], the timesince filter was fixed to work correctly with times that have a timezone attached. As a consequence of this, comparing a timezone-aware datetime value with a timezone-unaware (or timezone-naive) datetime returns a different result. Previously, it returned a completely incorrect result by just ignoring the timezone. Now, the error is handled in a more consistent (for Django) fashion by being treated as an actual error and returning an empty string. So the incorrect result will no longer display.

The "fix" here is to not compare two values unless they either both have timezones or both do not have timezones. Code that wasn't doing this was already broken previously. Now it will be more obvious.