Changes between Initial Version and Version 1 of OlderBackwardsIncompatibleChanges


Ignore:
Timestamp:
Mar 28, 2007, 9:44:52 PM (17 years ago)
Author:
Malcolm Tredinnick
Comment:

Moved really old backwards-incompat changes to this new page.

Legend:

Unmodified
Added
Removed
Modified
  • OlderBackwardsIncompatibleChanges

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