Code

Changes between Version 68 and Version 69 of BackwardsIncompatibleChanges


Ignore:
Timestamp:
12/10/06 07:52:31 (8 years ago)
Author:
anonymous
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • BackwardsIncompatibleChanges

    v68 v69  
    1 = Backwards-incompatible changes = 
    2  
    3 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. 
    4  
    5 Of course, once we reach 1.0, we'll be strongly committed to backward compatibility. 
    6  
    7 This page lists all backwards-incompatible changes to Django so far. 
    8  
    9 == Table of Contents == 
    10  
    11 Old-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  
    27 Changes 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  
    34 Changes 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  
    37 Changes 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  
    44 As 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  
    48 As of [292], syntax used for {{{order_by}}} (in the database API) and {{{ordering}}} (in models) has changed. 
    49  
    50 Example of old ordering syntax: 
    51 {{{order_by=[('foo', 'ASC'), ('bar', 'DESC')]}}} 
    52  
    53 Example of new ordering syntax: 
    54 {{{order_by=['foo', '-bar']}}} 
    55  
    56 The old syntax is deprecated, and we'll stop supporting it for 1.0. 
    57  
    58 == Refactored meta.py == 
    59  
    60 As 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  
    64 As of [440], using {{{edit_inline_type}}} in your models is deprecated, in favor of a less-redundant approach that uses {{{edit_inline}}} itself. 
    65  
    66 Example of old syntax: 
    67 {{{edit_inline=True, edit_inline_type=meta.TABULAR}}} 
    68  
    69 Example of new syntax: 
    70 {{{edit_inline=meta.TABULAR}}} 
    71  
    72 We'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  
    76 As 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  
    78 If 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  
    80 In PostgreSQL: 
    81  
    82 {{{ 
    83 BEGIN; 
    84 ALTER TABLE auth_admin_log RENAME object_id TO object_id_old; 
    85 ALTER TABLE auth_admin_log ADD COLUMN object_id TEXT; 
    86 UPDATE auth_admin_log SET object_id = object_id_old; 
    87 ALTER TABLE auth_admin_log DROP COLUMN object_id_old; 
    88 COMMIT; 
    89 }}} 
    90  
    91 In MySQL: 
    92  
    93 {{{ 
    94 ALTER TABLE auth_admin_log MODIFY object_id TEXT; 
    95 }}} 
    96  
    97 == Added support for anonymous sessions == 
    98  
    99 As 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  
    103 Add {{{"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  
    105 If 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  
    109 In PostgreSQL, use this: 
    110  
    111 {{{ 
    112 CREATE 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 ); 
    117 INSERT INTO content_types (name, package, python_module_name) VALUES ('session', 'core', 'sessions'); 
    118 }}} 
    119  
    120 In MySQL and SQLite, use this: 
    121  
    122 {{{ 
    123 CREATE 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 ); 
    128 INSERT INTO content_types (name, package, python_module_name) VALUES ('session', 'core', 'sessions'); 
    129 }}} 
    130  
    131 === Remove old, unneeded things === 
    132  
    133 Execute this SQL in your database: 
    134  
    135 {{{ 
    136 DROP TABLE auth_sessions; 
    137 DELETE FROM content_types WHERE package = 'auth' AND python_module_name = 'sessions'; 
    138 }}} 
    139  
    140 Edit your settings file(s) to remove {{{AUTH_SESSION_COOKIE}}} and {{{REGISTRATION_COOKIE_DOMAIN}}}, if they exist. 
    141  
    142 == Changed model syntax == 
    143  
    144 As 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  
    148 As 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  
    152 As 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  
    164 If 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  
    236 If 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  
    241 The 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  
    253 As 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  
    265 If 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  
    269 Execute the following SQL: 
    270  
    271 {{{ 
    272 DROP TABLE flatfiles; 
    273 DROP TABLE flatfiles_sites; 
    274 DELETE FROM auth_permissions WHERE package = 'core' AND codename IN ('add_flatfile', 'change_flatfile', 'delete_flatfile'); 
    275 DELETE FROM content_types WHERE package = 'core' AND python_module_name = 'flatfiles'; 
    276 }}} 
    277  
    278 ==== If you don't want to use redirects ==== 
    279  
    280 Execute the following SQL: 
    281  
    282 {{{ 
    283 DROP TABLE redirects; 
    284 DELETE FROM auth_permissions WHERE package = 'core' AND codename IN ('add_redirect', 'change_redirect', 'delete_redirect'); 
    285 DELETE 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  
    338 As 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  
    340 See 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  
    352 As 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  
    354 Execute the following SQL to restore auth functionality: 
    355  
    356  * PostgreSQL: 
    357 {{{ 
    358 BEGIN; 
    359 ALTER TABLE auth_users ADD COLUMN password varchar(128); 
    360 UPDATE auth_users SET password = password_md5; 
    361 ALTER TABLE auth_users ALTER COLUMN password SET NOT NULL; 
    362 ALTER TABLE auth_users DROP COLUMN password_md5; 
    363 COMMIT; 
    364 }}} 
    365  
    366  * MySQL: 
    367 {{{ 
    368 BEGIN; 
    369 ALTER TABLE `auth_users` CHANGE `password_md5` `password` VARCHAR(128) NOT NULL; 
    370 COMMIT; 
    371 }}} 
    372  
    373  * SQLite: 
    374 {{{ 
    375 BEGIN; 
    376 ALTER TABLE auth_users RENAME TO auth_users_old; 
    377 CREATE 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 ); 
    390 INSERT 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 ) 
    403 SELECT * FROM auth_users_old; 
    404 DROP TABLE auth_users_old; 
    405 COMMIT; 
    406 }}} 
    407  
    408 == Template system changes == 
    409  
    410 As 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  
    414 For any filters that don't take an argument, remove the second argument to the filter function. 
    415  
    416 Old: 
    417 {{{ 
    418 def lower(param, _): 
    419     return param.lower() 
    420 }}} 
    421  
    422 New: 
    423 {{{ 
    424 def lower(param): 
    425     return param.lower() 
    426 }}} 
    427  
    428 The 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  
    432 Old way: 
    433 {{{ 
    434 from django.core import template 
    435  
    436 template.register_filter('lower', lower, False) 
    437 template.register_tag('current_time', do_current_time) 
    438 }}} 
    439  
    440 New way: 
    441 {{{ 
    442 from django.core import template 
    443  
    444 register = template.Library() 
    445 register.filter('lower', lower) 
    446 register.tag('current_time', do_current_time) 
    447 }}} 
    448  
    449 === Change template decorator calls === 
    450  
    451 If you're using the undocumented template decorators (simple_tag and inclusion_tag), change your calls to be members of the library class. 
    452  
    453 Old way: 
    454 {{{ 
    455 simple_tag(func) 
    456 inclusion_tag('path/to/template')(func) 
    457 }}} 
    458  
    459 New way: 
    460 {{{ 
    461 register.simple_tag(func) 
    462 register.inclusion_tag('path/to/template')(func) 
    463 }}} 
    464  
    465 === Change template tags that use filters === 
    466  
    467 Filters are compiled at compile time now.  
    468  
    469 Old way: 
    470 {{{ 
    471 class 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  
    479 def do_something(parser, token): 
    480     bits = token.split() 
    481     filter_string = bits[1] 
    482     return SomethingNode(filter_string) 
    483  
    484 register_tag('something', do_something) 
    485 }}} 
    486  
    487 New way: 
    488 {{{ 
    489 class 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  
    497 def 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  
    503 register.tag('something', do_something) 
    504 }}} 
    505  
    506 See [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  
    510 Templates 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  
    514 As 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  
    516 For example, this old syntax: 
    517 {{{ 
    518 (r'^(?P<item_id>\d{1,3})/$', 'foo.item_detail'), 
    519 }}} 
    520  
    521 Can be shortened to this syntax: 
    522 {{{ 
    523 (r'^(\d{1,3})/$', 'foo.item_detail'), 
    524 }}} 
    525  
    526 The 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  
    528 The 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  
    530 There 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  
    542 In [1504], the {{{MultiValueDict}}} (and {{{QueryDict}}}) {{{items()}}} method was changed to return the *last* member of each list rather than the full list. 
    543  
    544 This probably doesn't affect anybody, but it's listed here for completeness. 
    545  
    546 Old behavior: 
    547 {{{ 
    548 >>> q = QueryDict('a=1&a=2') 
    549 >>> q.items() 
    550 [('a', ['1', 2'])] 
    551 }}} 
    552  
    553 New behavior: 
    554 {{{ 
    555 >>> q = QueryDict('a=1&a=2') 
    556 >>> q.items() 
    557 [('a', '2')] 
    558 }}} 
    559  
    560 To 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  
    570 As 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  
    574 As 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  
    578 As of [3512], the format of the constraint names Django generates for foreign key references changed slightly. These names are only used sometimes, when it is not possible to put the reference directly on the affected column, so this is not always visible. 
    579  
    580 The effect of this change is that {{{manage.py reset app_name}}} and similar commands may generate SQL with invalid constraint names and thus generate an error when run against the database (the database server will complain about the constraint not existing). To fix this, you will need to tweak the output of {{{manage.py sqlreset app_name}}} to match the correct constraint names and pass the results to the database server manually. 
    581  
    582 == Backslash escaping changed == 
    583  
    584 As of [3552], the Django database API now escapes backslashes given as query parameters. If you have any database API code that match backslashes, and it was working before (despite the broken escaping), you'll have to change your code to "unescape" the slashes one level. 
    585  
    586 For example, this used to work: 
    587  
    588 {{{ 
    589 #!python 
    590 # Code that matches a single backslash 
    591 MyModel.objects.filter(text__contains='\\\\') 
    592 }}} 
    593  
    594 But it should be rewritten as this: 
    595  
    596 {{{ 
    597 #!python 
    598 # Code that matches a single backslash 
    599 MyModel.objects.filter(text__contains='\\') 
    600 }}} 
    601  
    602 == Removed ENABLE_PSYCO setting == 
    603  
    604 As of [3877], the {{{ENABLE_PSYCO}}} setting no longer exists. If your settings file includes {{{ENABLE_PSYCO}}}, nothing will break per se, but it just won't do anything. If you want to use psyco with Django, write some custom middleware that activates psyco. 
     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 公关公司]