Changes between Version 69 and Version 70 of BackwardsIncompatibleChanges


Ignore:
Timestamp:
Dec 10, 2006, 1:31:33 PM (18 years ago)
Author:
JayK
Comment:

restoring page

Legend:

Unmodified
Added
Removed
Modified
  • BackwardsIncompatibleChanges

    v69 v70  
    1 [http://www.jingeyuqi.com.cn/index.asp 婚庆公司]
    2 [http://www.jingeyuqi.com.cn/index.asp 演出公司]
    3 [http://www.jingeyuqi.com.cn/index.asp 广告公司]
    4 [http://www.jingeyuqi.com.cn/product.asp 公关公司]
     1= Backwards-incompatible changes =
     2
     3As 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.
     4
     5Of course, once we reach 1.0, we'll be strongly committed to backward compatibility.
     6
     7This page lists all backwards-incompatible changes to Django so far.
     8
     9== Table of Contents ==
     10
     11Old-school Django (Pre-0.90)
     12 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Movedmod_pythonhandler Moved mod_python handler]
     13 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Changedorderingsyntax Changed ordering syntax]
     14 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Refactoredmeta.py Refactored meta.py]
     15 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Changededit_inlineandedit_inline_typebehavior Changed edit_inline and edit_inline_type behavior]
     16 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#ChangedadminlogtostoreprimarykeysasTEXTfieldsnotINTEGERfields Changed admin log to store primary keys as TEXT fields, not INTEGER fields]
     17 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Addedsupportforanonymoussessions Added support for anonymous sessions]
     18 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Changeyoursettingsfiles Change your settings files]
     19 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Createthecore_sessionsdatabasetable Create the core_sessions database table]
     20 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Removeoldunneededthings Remove old, unneeded things]
     21 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Changedmodelsyntax Changed model syntax]
     22 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Movedtemplateloadermodule Moved template loader module]
     23 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Refactoredtheadminappnottorequireitsownsettingsfile Refactored the admin app not to require its own settings file]
     24 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Separatedflatpagesandredirectsintostandaloneoptionalapps Separated flatpages and redirects into standalone, optional apps]
     25 * [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#RefactoredRSSframework Refactored RSS framework]
     26
     27Changes made after Django [source:/django/tags/releases/0.90 0.90]
     28 * Nov. 20: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Changedfieldnameandlengthforauth.Userpassword_md5field Changed field name and length for auth.User password_md5 field]
     29 * Nov. 26: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Templatesystemchanges Template system changes]
     30 * Nov. 27: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#AddedsupportfornonnamedgroupsinURLconfregularexpressions Added support for non-named groups in URLconf regular expressions]
     31 * Nov. 29: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#ChangedbehaviorofMultiValueDict.items Changed behavior of MultiValueDict.items()]
     32 * Nov. 30: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Removedundocumented_ordatabaseAPIparameter Removed undocumented '_or' database API parameter]
     33
     34Changes made after Django [source:/django/tags/releases/0.91 0.91]
     35 * May 1, 2006: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Removedthemagic Removed the magic]
     36
     37Changes made after Django [source:/django/tags/releases/0.95 0.95]
     38 * August 2, 2006: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Databaseconstraintnameschanged Database constraint names changed]
     39 * August 11, 2006: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#Backslashescapingchanged Backslash escaping changed]
     40 * September 27, 2006: [http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges#RemovedENABLE_PSYCOsetting Removed ENABLE_PSYCO setting]
     41
     42== Moved mod_python handler ==
     43
     44As of [169], using {{{django.core.handler}}} as a mod_python handler is deprecated. Use {{{django.core.handlers.modpython}}} instead. We will be removing {{{django.core.handler}}} for 1.0.
     45
     46== Changed ordering syntax ==
     47
     48As of [292], syntax used for {{{order_by}}} (in the database API) and {{{ordering}}} (in models) has changed.
     49
     50Example of old ordering syntax:
     51{{{order_by=[('foo', 'ASC'), ('bar', 'DESC')]}}}
     52
     53Example of new ordering syntax:
     54{{{order_by=['foo', '-bar']}}}
     55
     56The old syntax is deprecated, and we'll stop supporting it for 1.0.
     57
     58== Refactored meta.py ==
     59
     60As of [378], {{{django/core/meta.py}}} has been converted to a package, {{{django/core/meta/}}}. If you're using a version of Django from before [378], make sure to delete {{{django/core/meta.pyc}}} and {{{django/core/meta.pyo}}}, if they exist. The existence of those files doesn't pose any known problems, but it's best to clean things up.
     61
     62== Changed edit_inline and edit_inline_type behavior ==
     63
     64As of [440], using {{{edit_inline_type}}} in your models is deprecated, in favor of a less-redundant approach that uses {{{edit_inline}}} itself.
     65
     66Example of old syntax:
     67{{{edit_inline=True, edit_inline_type=meta.TABULAR}}}
     68
     69Example of new syntax:
     70{{{edit_inline=meta.TABULAR}}}
     71
     72We'll stop supporting the old syntax for 1.0.
     73
     74== Changed admin log to store primary keys as TEXT fields, not INTEGER fields ==
     75
     76As of [469], the {{{object_id}}} field in {{{django.models.auth.LogEntry}}} is a {{{TextField}}} instead of an {{{IntegerField}}}. We made this change to accomodate non-integer primary keys.
     77
     78If you're using a Django database installation from before [469] and you want to use non-integer primary keys on an object you edit in the admin site, you'll need to do an {{{ALTER TABLE}}} in your database.
     79
     80In PostgreSQL:
     81
     82{{{
     83BEGIN;
     84ALTER TABLE auth_admin_log RENAME object_id TO object_id_old;
     85ALTER TABLE auth_admin_log ADD COLUMN object_id TEXT;
     86UPDATE auth_admin_log SET object_id = object_id_old;
     87ALTER TABLE auth_admin_log DROP COLUMN object_id_old;
     88COMMIT;
     89}}}
     90
     91In MySQL:
     92
     93{{{
     94ALTER TABLE auth_admin_log MODIFY object_id TEXT;
     95}}}
     96
     97== Added support for anonymous sessions ==
     98
     99As of [518], Django has support for anonymous sessions. If you're using a Django database installation from before [518] and you want to use the Django admin, anonymous sessions or auth-based sessions, you'll need to make a few updates to your database and settings files.
     100
     101=== Change your settings files ===
     102
     103Add {{{"django.middleware.sessions.SessionMiddleware"}}} to the {{{MIDDLEWARE_CLASSES}}} tuple in your admin settings file. Make sure it appears before {{{"django.middleware.admin.AdminUserRequired"}}}. (The middleware classes are applied in order, and the admin middleware requires that the session middleware come first.)
     104
     105If you want session support any other (i.e., non-admin) Django installation, change the {{{MIDDLEWARE_CLASSES}}} setting accordingly. The order (i.e., whether it comes before or after the other installed middleware classes) doesn't matter.
     106
     107=== Create the core_sessions database table ===
     108
     109In PostgreSQL, use this:
     110
     111{{{
     112CREATE TABLE core_sessions (
     113    session_key varchar(40) NOT NULL PRIMARY KEY,
     114    session_data text NOT NULL,
     115    expire_date timestamp with time zone NOT NULL
     116);
     117INSERT INTO content_types (name, package, python_module_name) VALUES ('session', 'core', 'sessions');
     118}}}
     119
     120In MySQL and SQLite, use this:
     121
     122{{{
     123CREATE TABLE core_sessions (
     124    session_key varchar(40) NOT NULL PRIMARY KEY,
     125    session_data text NOT NULL,
     126    expire_date datetime NOT NULL
     127);
     128INSERT INTO content_types (name, package, python_module_name) VALUES ('session', 'core', 'sessions');
     129}}}
     130
     131=== Remove old, unneeded things ===
     132
     133Execute this SQL in your database:
     134
     135{{{
     136DROP TABLE auth_sessions;
     137DELETE FROM content_types WHERE package = 'auth' AND python_module_name = 'sessions';
     138}}}
     139
     140Edit your settings file(s) to remove {{{AUTH_SESSION_COOKIE}}} and {{{REGISTRATION_COOKIE_DOMAIN}}}, if they exist.
     141
     142== Changed model syntax ==
     143
     144As of [549], Django's model syntax has changed. If you're using models that use old (pre-[549]) syntax, you'll need to convert them according to the instructions on ModelSyntaxChangeInstructions.
     145
     146== Moved template loader module ==
     147
     148As of [867], {{{django.core.template_loader}}} is deprecated. Use {{{django.core.template.loader}}} instead.
     149
     150== Refactored the admin app not to require its own settings file ==
     151
     152As of [948], the admin has been refactored, to make things simpler and tighter -- both conceptually and in code layout.
     153
     154=== What changed ===
     155
     156 * The admin no longer requires its own settings file. The "main" site and admin site can run on the same Django installation.
     157 * All the admin code moved to {{{django/contrib/admin}}}.
     158 * The admin requires {{{"django.contrib.admin"}}} in {{{INSTALLED_APPS}}}, and it requires the {{{app_directories}}} [http://www.djangoproject.com/documentation/templates_python/#loader-types template loader].
     159 * The admin database table isn't installed unless you explicitly have the admin installed ({{{django-admin.py install admin}}}).
     160 * Renamed the admin log database table to give it a {{{"django"}}} prefix.
     161
     162=== How to update your code ===
     163
     164If you're using a Django installation from before this changeset, do the following to restore your admin site:
     165
     166 * Execute this SQL command: {{{ALTER TABLE auth_admin_log RENAME TO django_admin_log;}}}
     167 * If you're using an SQLite version older than 3.2.0 (no ALTER TABLE support), execute these SQL commands (following [http://www.sqlite.org/faq.html#q13 this pattern]):
     168   {{{
     169   BEGIN TRANSACTION;
     170   CREATE TEMPORARY TABLE auth_backup (
     171    id integer NOT NULL PRIMARY KEY,
     172    action_time datetime NOT NULL,
     173    user_id integer NOT NULL REFERENCES auth_users (id),
     174    content_type_id integer NULL REFERENCES content_types (id),
     175    object_id text NULL,
     176    object_repr varchar(200) NOT NULL,
     177    action_flag smallint unsigned NOT NULL,
     178    change_message text NOT NULL
     179   );
     180   INSERT INTO auth_backup SELECT id, action_time, user_id, content_type_id, object_id, object_repr, action_flag, change_message FROM auth_admin_log;
     181   DROP TABLE auth_admin_log;
     182   CREATE TABLE django_admin_log (
     183    id integer NOT NULL PRIMARY KEY,
     184    action_time datetime NOT NULL,
     185    user_id integer NOT NULL REFERENCES auth_users (id),
     186    content_type_id integer NULL REFERENCES content_types (id),
     187    object_id text NULL,
     188    object_repr varchar(200) NOT NULL,
     189    action_flag smallint unsigned NOT NULL,
     190    change_message text NOT NULL
     191   );
     192   INSERT INTO django_admin_log SELECT id, action_time, user_id, content_type_id, object_id, object_repr, action_flag, change_message FROM auth_backup;
     193   DROP TABLE auth_backup;
     194   COMMIT;
     195   }}}
     196 * If you're using PostgreSQL, execute these SQL commands:
     197   {{{
     198   ALTER TABLE auth_admin_log_id_seq RENAME TO django_admin_log_id_seq;
     199   ALTER TABLE django_admin_log ALTER COLUMN id DROP DEFAULT;
     200   ALTER TABLE django_admin_log ALTER COLUMN id SET DEFAULT nextval('public.django_admin_log_id_seq'::text);
     201   }}}
     202 * Edit your Django settings file (probably called {{{settings/main.py}}}) to make the following changes:
     203   * Add {{{"django.contrib.admin"}}} to {{{INSTALLED_APPS}}}. Order doesn't matter; it can be the first, last, whatever.
     204   * Remove {{{"django.middleware.admin.AdminUserRequired"}}} from {{{MIDDLEWARE_CLASSES}}}, if it's in there.
     205   * Add {{{"django.middleware.sessions.SessionMiddleware"}}} to {{{MIDDLEWARE_CLASSES}}}, if it's not already in there.
     206   * If you've created any custom admin templates, add the appropriate line from the admin {{{TEMPLATE_DIRS}}} setting to your "main" {{{TEMPLATE_DIRS}}}.
     207     * (Note that Django looks for "404.html" and "500.html" templates in your {{{TEMPLATE_DIRS}}}. Make sure you have these templates available.)
     208   * If you've created any custom admin templates, note that the template inheritance structure has changed. All admin templates are now within an {{{admin}}} subdirectory of the template directory. The following admin templates are directly affected by this change:
     209     * 404 --> admin/404
     210     * 500 --> admin/500
     211     * base --> admin/base
     212     * base_site --> admin/base_site
     213     * admin_object_history --> admin/object_history
     214     * delete_confirmation_generic --> admin/delete_confirmation
     215     * index --> admin/index
     216     * login --> admin/login
     217     * template_validator --> admin/template_validator
     218   * Add {{{"django.core.template.loaders.app_directories.load_template_source"}}} to {{{TEMPLATE_LOADERS}}}, after {{{"django.core.template.loaders.filesystem.load_template_source"}}}. If you don't have the {{{TEMPLATE_LOADERS}}} setting, set it to this:
     219     {{{
     220     TEMPLATE_LOADERS = (
     221         'django.core.template.loaders.filesystem.load_template_source',
     222         'django.core.template.loaders.app_directories.load_template_source',
     223     )
     224     }}}
     225
     226 * Remove your admin settings file (probably called {{{settings/admin.py}}}) and admin URLconf (probably called {{{settings/urls/admin.py}}}).
     227 * Delete {{{django/templatetags/*.pyc}}} and {{{django/templatetags/*.pyo}}}, just to be safe.
     228 * Edit your main URLconf (probably called {{{settings/urls/main.py}}}) and add this line:
     229
     230     {{{
     231     (r'^admin/', include('django.contrib.admin.urls.admin')),
     232     }}}
     233
     234   Change that {{{"admin"}}} to whatever URL you were using for the admin site.
     235
     236If you use external mapping to files and directories (e.g., using mod_rewrite), do the following:
     237
     238 * Make sure you're not redirecting {{{/admin}}} to another instance of Django with different settings (e.g., using settings/admin.py).
     239 * If you had a mapping of admin media files, make sure that it points to new directory, which is {{{/your/path/to/django/contrib/admin/media}}}.
     240
     241The following steps are optional but will tighten your code up. All assume your project is called {{{myproject}}}.
     242
     243 * Move {{{myproject/settings/urls/main.py}}} to {{{myproject/urls.py}}}.
     244 * Delete {{{myproject/settings/urls/admin.py}}} (unless you had custom things in it, of course).
     245 * Move {{{myproject/settings/main.py}}} to {{{myproject/settings.py}}}.
     246 * Edit {{{myproject/settings.py}}} to change {{{ROOT_URLCONF}}} from {{{"myproject.settings.urls.main"}}} to {{{"myproject.urls"}}}.
     247 * If you use {{{myproject/settings/main_rss.py}}} to describe your RSS feeds, move it to {{{myproject/settings_rss.py}}}.
     248 * Change {{{DJANGO_SETTINGS_MODULE}}} in Apache configuration from {{{"myproject.settings.main"}}} to {{{"myproject.settings"}}}.
     249 * Having done all this, delete the directory {{{myproject/settings}}}.
     250
     251== Separated flatpages and redirects into standalone, optional apps ==
     252
     253As of [1166], flatpages and redirects, previously installed by default, are now optional add-ons. Now they must be installed manually.
     254
     255=== What changed ===
     256
     257 * The flatpages and redirects database files are no longer installed by default.
     258 * Renamed all references to "flatfiles" -- a previous name for flatpages -- to "flatpages", to be unambiguous.
     259 * Renamed the flatpages and redirects database tables.
     260 * Moved all flatpages and redirects logic from throughout the Django code to {{{django.contrib}}}.
     261 * To use flatpages and redirects, you now need to specify them in {{{INSTALLED_APPS}}} -- use {{{"django.contrib.flatpages"}}} and {{{"django.contrib.redirects"}}}.
     262
     263=== How to update your code ===
     264
     265If you're using a Django installation from before this changeset, do the following to restore flatpages and redirects functionality:
     266
     267==== If you don't want to use flatfiles ====
     268
     269Execute the following SQL:
     270
     271{{{
     272DROP TABLE flatfiles;
     273DROP TABLE flatfiles_sites;
     274DELETE FROM auth_permissions WHERE package = 'core' AND codename IN ('add_flatfile', 'change_flatfile', 'delete_flatfile');
     275DELETE FROM content_types WHERE package = 'core' AND python_module_name = 'flatfiles';
     276}}}
     277
     278==== If you don't want to use redirects ====
     279
     280Execute the following SQL:
     281
     282{{{
     283DROP TABLE redirects;
     284DELETE FROM auth_permissions WHERE package = 'core' AND codename IN ('add_redirect', 'change_redirect', 'delete_redirect');
     285DELETE FROM content_types WHERE package = 'core' AND python_module_name = 'redirects';
     286}}}
     287
     288==== If you want to use flatfiles ====
     289
     290 * If you're using PostgreSQL, execute the following:
     291   {{{
     292   ALTER TABLE flatfiles RENAME TO django_flatpages;
     293   ALTER TABLE flatfiles_sites RENAME TO django_flatpages_sites;
     294   ALTER TABLE django_flatpages_sites RENAME flatfile_id TO flatpage_id;
     295   INSERT INTO packages (label, name) VALUES ('flatpages', 'flatpages');
     296   UPDATE content_types SET package = 'flatpages', python_module_name = 'flatpages' WHERE package = 'core' AND python_module_name = 'flatfiles';
     297   UPDATE auth_permissions SET package = 'flatpages' WHERE package = 'core' AND codename IN ('add_flatfile', 'change_flatfile', 'delete_flatfile');
     298   ALTER TABLE flatfiles_id_seq RENAME TO django_flatpages_id_seq;
     299   ALTER TABLE django_flatpages ALTER COLUMN id DROP DEFAULT;
     300   ALTER TABLE django_flatpages ALTER COLUMN id SET DEFAULT nextval('public.django_flatpages_id_seq'::text);
     301   }}}
     302 * If you're using MySQL, execute the following:
     303   {{{
     304   ALTER TABLE flatfiles RENAME TO django_flatpages;
     305   ALTER TABLE flatfiles_sites RENAME TO django_flatpages_sites;
     306   ALTER TABLE django_flatpages_sites CHANGE flatfile_id flatpage_id INTEGER;
     307   INSERT INTO packages (label, name) VALUES ('flatpages', 'flatpages');
     308   UPDATE content_types SET package = 'flatpages', python_module_name = 'flatpages' WHERE package = 'core' AND python_module_name = 'flatfiles';
     309   UPDATE auth_permissions SET package = 'flatpages' WHERE package = 'core' AND codename IN ('add_flatfile', 'change_flatfile', 'delete_flatfile');
     310   }}}
     311 * If you have a {{{flatfiles/default.html}}} template, rename it to {{{flatpages/default.html}}}.
     312 * In every one of your flatpage templates, change the variable {{{flatfile}}} to {{{flatpage}}}.
     313 * If you use the URLconf {{{django.conf.urls.flatfiles}}}, now point to {{{django.contrib.flatpages.urls}}}.
     314 * If you have a {{{USE_FLAT_PAGES}}} setting, remove it.
     315 * Add {{{"django.contrib.flatpages"}}} to your {{{INSTALLED_APPS}}}.
     316 * Add {{{"django.contrib.flatpages.middleware.FlatpageFallbackMiddleware"}}} to your {{{MIDDLEWARE_CLASSES}}}.
     317
     318==== If you want to use redirects ====
     319
     320 * Execute the following SQL:
     321   {{{
     322   ALTER TABLE redirects RENAME TO django_redirects;
     323   INSERT INTO packages (label, name) VALUES ('redirects', 'redirects');
     324   UPDATE content_types SET package = 'redirects', python_module_name = 'redirects' WHERE package = 'core' AND python_module_name = 'redirects';
     325   UPDATE auth_permissions SET package = 'redirects' WHERE package = 'core' AND codename IN ('add_redirect', 'change_redirect', 'delete_redirect');
     326   }}}
     327 * If you're using PostgreSQL, execute this additional SQL:
     328   {{{
     329   ALTER TABLE redirects_id_seq RENAME TO django_redirects_id_seq;
     330   ALTER TABLE django_redirects ALTER COLUMN id DROP DEFAULT;
     331   ALTER TABLE django_redirects ALTER COLUMN id SET DEFAULT nextval('public.django_redirects_id_seq'::text);
     332   }}}
     333 * Add {{{"django.contrib.redirects"}}} to your {{{INSTALLED_APPS}}}.
     334 * Add {{{"django.contrib.redirects.middleware.RedirectFallbackMiddleware"}}} to your {{{MIDDLEWARE_CLASSES}}}.
     335
     336== Refactored RSS framework ==
     337
     338As of [1194], Django's RSS framework was refactored. This change should not affect most Django users, because the RSS framework was completely undocumented. The only users affected are people who reverse-engineered the framework, and WorldOnline.
     339
     340See the new [http://www.djangoproject.com/documentation/syndication/ syndication docs]. For completeness, here's what changed:
     341
     342 * Created {{{django/contrib/syndication}}}.
     343 * Removed {{{django/conf/urls/rss.py}}}. The syndication system doesn't require its own URLconf anymore.
     344 * Moved {{{django/views/rss/rss.py}}} to {{{django/contrib/syndication/views.py}}} and refactored it so that {{{feed()}}} takes {{{url}}} and {{{feed_dict}}} instead of {{{slug}}} and {{{param}}}.
     345 * Renamed {{{DefaultRssFeed}}} to {{{DefaultFeed}}} in {{{django/utils/feedgenerator.py}}}.
     346 * RSS feeds are now specified as subclasses of {{{django.contrib.syndication.feeds.Feed}}} instead of {{{django.core.rss.FeedConfiguration}}}. Syntax is completely different.
     347 * RSS feeds are now registered in URLconfs rather than in "magic" settings modules whose names end with "_rss".
     348 * Templates for RSS titles and descriptions now live in a {{{feeds}}} directory, not an {{{rss}}} directory.
     349
     350== Changed field name and length for auth.User password_md5 field ==
     351
     352As of [1327], the {{{password_md5}}} field in the {{{auth.User}}} model, which is used for authentication in the Django admin, was renamed to {{{password}}}, and its length was changed from 32 to 128 to accomodate longer hashes and password metadata, such as which hash algorithm to use. This affects everybody who uses the Django authentication system -- including users of the Django admin.
     353
     354Execute the following SQL to restore auth functionality:
     355
     356 * PostgreSQL:
     357{{{
     358BEGIN;
     359ALTER TABLE auth_users ADD COLUMN password varchar(128);
     360UPDATE auth_users SET password = password_md5;
     361ALTER TABLE auth_users ALTER COLUMN password SET NOT NULL;
     362ALTER TABLE auth_users DROP COLUMN password_md5;
     363COMMIT;
     364}}}
     365
     366 * MySQL:
     367{{{
     368BEGIN;
     369ALTER TABLE `auth_users` CHANGE `password_md5` `password` VARCHAR(128) NOT NULL;
     370COMMIT;
     371}}}
     372
     373 * SQLite:
     374{{{
     375BEGIN;
     376ALTER TABLE auth_users RENAME TO auth_users_old;
     377CREATE TABLE auth_users (
     378    id integer NOT NULL PRIMARY KEY,
     379    username varchar(30) NOT NULL UNIQUE,
     380    first_name varchar(30) NOT NULL,
     381    last_name varchar(30) NOT NULL,
     382    email varchar(75) NOT NULL,
     383    password varchar(128) NOT NULL,
     384    is_staff bool NOT NULL,
     385    is_active bool NOT NULL,
     386    is_superuser bool NOT NULL,
     387    last_login datetime NOT NULL,
     388    date_joined datetime NOT NULL
     389);
     390INSERT INTO auth_users (
     391        id,
     392        username,
     393        first_name,
     394        last_name,
     395        email,
     396        password,
     397        is_staff,
     398        is_active,
     399        is_superuser,
     400        last_login,
     401        date_joined
     402)
     403SELECT * FROM auth_users_old;
     404DROP TABLE auth_users_old;
     405COMMIT;
     406}}}
     407
     408== Template system changes ==
     409
     410As of [1443], we changed the way custom template tags and filters are registered. If you've written custom template tags or filters, you'll need to make a couple of changes:
     411
     412=== Filter arguments ===
     413
     414For any filters that don't take an argument, remove the second argument to the filter function.
     415
     416Old:
     417{{{
     418def lower(param, _):
     419    return param.lower()
     420}}}
     421
     422New:
     423{{{
     424def lower(param):
     425    return param.lower()
     426}}}
     427
     428The system now introspects the function's arguments to find out whether a filter argument is required.
     429
     430=== Change the way your tags/filters are registered ===
     431
     432Old way:
     433{{{
     434from django.core import template
     435
     436template.register_filter('lower', lower, False)
     437template.register_tag('current_time', do_current_time)
     438}}}
     439
     440New way:
     441{{{
     442from django.core import template
     443
     444register = template.Library()
     445register.filter('lower', lower)
     446register.tag('current_time', do_current_time)
     447}}}
     448
     449=== Change template decorator calls ===
     450
     451If you're using the undocumented template decorators (simple_tag and inclusion_tag), change your calls to be members of the library class.
     452
     453Old way:
     454{{{
     455simple_tag(func)
     456inclusion_tag('path/to/template')(func)
     457}}}
     458
     459New way:
     460{{{
     461register.simple_tag(func)
     462register.inclusion_tag('path/to/template')(func)
     463}}}
     464
     465=== Change template tags that use filters ===
     466
     467Filters are compiled at compile time now.
     468
     469Old way:
     470{{{
     471class SomethingNode(Node):
     472    def __init__(self, filter_string):
     473        self.filter_string = filter_string
     474
     475    def render(self, context):
     476        var = resolve_variable_with_filters(self.filter_string, context)
     477        return var
     478
     479def do_something(parser, token):
     480    bits = token.split()
     481    filter_string = bits[1]
     482    return SomethingNode(filter_string)
     483
     484register_tag('something', do_something)
     485}}}
     486
     487New way:
     488{{{
     489class SomethingNode(Node):
     490    def __init__(self, filter_expr):
     491        self.filter_expr = filter_expr
     492
     493    def render(self, context):
     494        var = self.filter_expr.resolve(context)
     495        return var
     496
     497def do_something(parser, token):
     498    bits = token.split()
     499    filter_string = bits[1]
     500    filter_expr = parser.compile_filter(filter_string)
     501    return SomethingNode(filter_expr)
     502
     503register.tag('something', do_something)
     504}}}
     505
     506See [http://www.djangoproject.com/documentation/templates_python/#writing-custom-template-filters Writing custom template filters] and [http://www.djangoproject.com/documentation/templates_python/#writing-custom-template-tags Writing custom template tags] for full documentation.
     507
     508=== Templates ===
     509
     510Templates that are included in another template using {{{{% include %}}}} or {{{{% ssi %}}}}, or extend a template using {{{{% extends %}}}}, must explicitly {{{{% load %}}}} all libraries they need for their tags and filters. Some templates may have worked in the past due to previous requests registering tags : this will no longer work.
     511
     512== Added support for non-named groups in URLconf regular expressions ==
     513
     514As of [1470], Django URLconfs support non-named groups in URLconf regular expressions. This means you no longer have to specify the name of each group.
     515
     516For example, this old syntax:
     517{{{
     518(r'^(?P<item_id>\d{1,3})/$', 'foo.item_detail'),
     519}}}
     520
     521Can be shortened to this syntax:
     522{{{
     523(r'^(\d{1,3})/$', 'foo.item_detail'),
     524}}}
     525
     526The algorithm it follows is: If there are any named groups, it will use those, ignoring all non-named groups. Otherwise, it will pass all non-named groups as positional arguments. In both cases, it will pass any {{{extra_kwargs}}} as keyword arguments.
     527
     528The old syntax (named groups) still works. Use that in cases where you can't (or don't want to) couple the order of URL parameters with the order of your view function arguments.
     529
     530There are two small backwards-incompatibilities about this change:
     531
     532 * If you've written custom middleware that implements {{{process_view()}}}, you'll need to change it so it takes {{{view_args}}} and {{{view_kwargs}}} arguments instead of {{{param_dict}}}:
     533
     534   {{{
     535   def process_view(self, request, view_func, view_args, view_kwargs)
     536   }}}
     537
     538 * On the off chance you have legacy URLconfs that have NO captured items but DO use capturing parenthesis (which until now would have had no effect), you'll need to either change your view code to accept the captured values, or uncapture them.
     539
     540== Changed behavior of MultiValueDict.items() ==
     541
     542In [1504], the {{{MultiValueDict}}} (and {{{QueryDict}}}) {{{items()}}} method was changed to return the *last* member of each list rather than the full list.
     543
     544This probably doesn't affect anybody, but it's listed here for completeness.
     545
     546Old behavior:
     547{{{
     548>>> q = QueryDict('a=1&a=2')
     549>>> q.items()
     550[('a', ['1', 2'])]
     551}}}
     552
     553New behavior:
     554{{{
     555>>> q = QueryDict('a=1&a=2')
     556>>> q.items()
     557[('a', '2')]
     558}}}
     559
     560To emulate the old behavior, use the new {{{lists()}}} method:
     561
     562{{{
     563>>> q = QueryDict('a=1&a=2')
     564>>> q.lists()
     565[('a', ['1', 2'])]
     566}}}
     567
     568== Removed undocumented '_or' database API parameter ==
     569
     570As of [1508], the {{{_or}}} parameter no longer works. Use the new {{{complex}}} parameter. This likely doesn't affect anybody except World Online, because {{{_or}}} has been undocumented and vehemently discouraged on the mailing list.
     571
     572== Removed the magic ==
     573
     574As of [2809], the [wiki:RemovingTheMagic magic-removal branch] has been merged. There's a LONG list of backwards-incompatible changes, and they're all documented on the RemovingTheMagic wiki page.
     575
     576== Database constraint names changed ==
     577
     578As 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.
     579
     580The 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.
     581
     582== Backslash escaping changed ==
     583
     584As 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.
     585
     586For example, this used to work:
     587
     588{{{
     589#!python
     590# Code that matches a single backslash
     591MyModel.objects.filter(text__contains='\\\\')
     592}}}
     593
     594But it should be rewritten as this:
     595
     596{{{
     597#!python
     598# Code that matches a single backslash
     599MyModel.objects.filter(text__contains='\\')
     600}}}
     601
     602== Removed ENABLE_PSYCO setting ==
     603
     604As 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.
Back to Top