1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
|
=========================================
Porting your apps from Django 0.96 to 1.0
=========================================
.. highlight:: python
Django 1.0 breaks compatibility with 0.96 in some areas.
This guide will help you port 0.96 projects and apps to 1.0. The first part of
this document includes the common changes needed to run with 1.0. If after going
through the first part your code still breaks, check the section `Less-common
Changes`_ for a list of a bunch of less-common compatibility issues.
.. seealso::
The :doc:`1.0 release notes </releases/1.0>`. That document explains the new
features in 1.0 more deeply; the porting guide is more concerned with
helping you quickly update your code.
Common changes
==============
This section describes the changes between 0.96 and 1.0 that most users will
need to make.
Use Unicode
-----------
Change string literals (``'foo'``) into Unicode literals (``u'foo'``). Django
now uses Unicode strings throughout. In most places, raw strings will continue
to work, but updating to use Unicode literals will prevent some obscure
problems.
See :doc:`/ref/unicode` for full details.
Models
------
Common changes to your models file:
Rename ``maxlength`` to ``max_length``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Rename your ``maxlength`` argument to ``max_length`` (this was changed to be
consistent with form fields):
Replace ``__str__`` with ``__unicode__``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replace your model's ``__str__`` function with a ``__unicode__`` method, and
make sure you `use Unicode`_ (``u'foo'``) in that method.
Remove ``prepopulated_from``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Remove the ``prepopulated_from`` argument on model fields. It's no longer valid
and has been moved to the ``ModelAdmin`` class in ``admin.py``. See `the
admin`_, below, for more details about changes to the admin.
Remove ``core``
~~~~~~~~~~~~~~~
Remove the ``core`` argument from your model fields. It is no longer
necessary, since the equivalent functionality (part of :ref:`inline editing
<admin-inlines>`) is handled differently by the admin interface now. You don't
have to worry about inline editing until you get to `the admin`_ section,
below. For now, remove all references to ``core``.
Replace ``class Admin:`` with ``admin.py``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Remove all your inner ``class Admin`` declarations from your models. They won't
break anything if you leave them, but they also won't do anything. To register
apps with the admin you'll move those declarations to an ``admin.py`` file;
see `the admin`_ below for more details.
.. seealso::
A contributor to djangosnippets__ has written a script that'll `scan your
models.py and generate a corresponding admin.py`__.
__ http://www.djangosnippets.org/
__ http://www.djangosnippets.org/snippets/603/
Example
~~~~~~~
Below is an example ``models.py`` file with all the changes you'll need to make:
Old (0.96) ``models.py``::
class Author(models.Model):
first_name = models.CharField(maxlength=30)
last_name = models.CharField(maxlength=30)
slug = models.CharField(maxlength=60, prepopulate_from=('first_name', 'last_name'))
class Admin:
list_display = ['first_name', 'last_name']
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
New (1.0) ``models.py``::
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
slug = models.CharField(max_length=60)
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
New (1.0) ``admin.py``::
from django.contrib import admin
from models import Author
class AuthorAdmin(admin.ModelAdmin):
list_display = ['first_name', 'last_name']
prepopulated_fields = {
'slug': ('first_name', 'last_name')
}
admin.site.register(Author, AuthorAdmin)
The Admin
---------
One of the biggest changes in 1.0 is the new admin. The Django administrative
interface (``django.contrib.admin``) has been completely refactored; admin
definitions are now completely decoupled from model definitions, the framework
has been rewritten to use Django's new form-handling library and redesigned with
extensibility and customization in mind.
Practically, this means you'll need to rewrite all of your ``class Admin``
declarations. You've already seen in `models`_ above how to replace your ``class
Admin`` with a ``admin.site.register()`` call in an ``admin.py`` file. Below are
some more details on how to rewrite that ``Admin`` declaration into the new
syntax.
Use new inline syntax
~~~~~~~~~~~~~~~~~~~~~
The new ``edit_inline`` options have all been moved to ``admin.py``. Here's an
example:
Old (0.96)::
class Parent(models.Model):
...
class Child(models.Model):
parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)
New (1.0)::
class ChildInline(admin.StackedInline):
model = Child
extra = 3
class ParentAdmin(admin.ModelAdmin):
model = Parent
inlines = [ChildInline]
admin.site.register(Parent, ParentAdmin)
See :ref:`admin-inlines` for more details.
Simplify ``fields``, or use ``fieldsets``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The old ``fields`` syntax was quite confusing, and has been simplified. The old
syntax still works, but you'll need to use ``fieldsets`` instead.
Old (0.96)::
class ModelOne(models.Model):
...
class Admin:
fields = (
(None, {'fields': ('foo','bar')}),
)
class ModelTwo(models.Model):
...
class Admin:
fields = (
('group1', {'fields': ('foo','bar'), 'classes': 'collapse'}),
('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
)
New (1.0)::
class ModelOneAdmin(admin.ModelAdmin):
fields = ('foo', 'bar')
class ModelTwoAdmin(admin.ModelAdmin):
fieldsets = (
('group1', {'fields': ('foo','bar'), 'classes': 'collapse'}),
('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
)
.. seealso::
* More detailed information about the changes and the reasons behind them
can be found on the `NewformsAdminBranch wiki page`__
* The new admin comes with a ton of new features; you can read about them in
the :doc:`admin documentation </ref/contrib/admin/index>`.
__ http://code.djangoproject.com/wiki/NewformsAdminBranch
URLs
----
Update your root ``urls.py``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're using the admin site, you need to update your root ``urls.py``.
Old (0.96) ``urls.py``::
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls')),
# ... the rest of your URLs here ...
)
New (1.0) ``urls.py``::
from django.conf.urls.defaults import *
# The next two lines enable the admin and load each admin.py file:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
# ... the rest of your URLs here ...
)
Views
-----
Use ``django.forms`` instead of ``newforms``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replace ``django.newforms`` with ``django.forms`` -- Django 1.0 renamed the
``newforms`` module (introduced in 0.96) to plain old ``forms``. The
``oldforms`` module was also removed.
If you're already using the ``newforms`` library, and you used our recommended
``import`` statement syntax, all you have to do is change your import
statements.
Old::
from django import newforms as forms
New::
from django import forms
If you're using the old forms system (formerly known as ``django.forms`` and
``django.oldforms``), you'll have to rewrite your forms. A good place to start
is the :doc:`forms documentation </topics/forms/index>`
Handle uploaded files using the new API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replace use of uploaded files -- that is, entries in ``request.FILES`` -- as
simple dictionaries with the new :class:`~django.core.files.UploadedFile`. The
old dictionary syntax no longer works.
Thus, in a view like::
def my_view(request):
f = request.FILES['file_field_name']
...
...you'd need to make the following changes:
===================== =====================
Old (0.96) New (1.0)
===================== =====================
``f['content']`` ``f.read()``
``f['filename']`` ``f.name``
``f['content-type']`` ``f.content_type``
===================== =====================
Work with file fields using the new API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The internal implementation of :class:`django.db.models.FileField` have changed.
A visible result of this is that the way you access special attributes (URL,
filename, image size, etc) of these model fields has changed. You will need to
make the following changes, assuming your model's
:class:`~django.db.models.FileField` is called ``myfile``:
=================================== ========================
Old (0.96) New (1.0)
=================================== ========================
``myfile.get_content_filename()`` ``myfile.content.path``
``myfile.get_content_url()`` ``myfile.content.url``
``myfile.get_content_size()`` ``myfile.content.size``
``myfile.save_content_file()`` ``myfile.content.save()``
``myfile.get_content_width()`` ``myfile.content.width``
``myfile.get_content_height()`` ``myfile.content.height``
=================================== ========================
Note that the ``width`` and ``height`` attributes only make sense for
:class:`~django.db.models.ImageField` fields. More details can be found in the
:doc:`model API </ref/models/fields>` documentation.
Use ``Paginator`` instead of ``ObjectPaginator``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``ObjectPaginator`` in 0.96 has been removed and replaced with an improved
version, :class:`django.core.paginator.Paginator`.
Templates
---------
Learn to love autoescaping
~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, the template system now automatically HTML-escapes the output of
every variable. To learn more, see :ref:`automatic-html-escaping`.
To disable auto-escaping for an individual variable, use the :tfilter:`safe`
filter:
.. code-block:: html+django
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
To disable auto-escaping for an entire template, wrap the template (or just a
particular section of the template) in the :ttag:`autoescape` tag:
.. code-block:: html+django
{% autoescape off %}
... unescaped template content here ...
{% endautoescape %}
Less-common changes
===================
The following changes are smaller, more localized changes. They should only
affect more advanced users, but it's probably worth reading through the list and
checking your code for these things.
Signals
-------
* Add ``**kwargs`` to any registered signal handlers.
* Connect, disconnect, and send signals via methods on the
:class:`~django.dispatch.Signal` object instead of through module methods in
``django.dispatch.dispatcher``.
* Remove any use of the ``Anonymous`` and ``Any`` sender options; they no longer
exist. You can still receive signals sent by any sender by using
``sender=None``
* Make any custom signals you've declared into instances of
:class:`django.dispatch.Signal` instead of anonymous objects.
Here's quick summary of the code changes you'll need to make:
================================================= ======================================
Old (0.96) New (1.0)
================================================= ======================================
``def callback(sender)`` ``def callback(sender, **kwargs)``
``sig = object()`` ``sig = django.dispatch.Signal()``
``dispatcher.connect(callback, sig)`` ``sig.connect(callback)``
``dispatcher.send(sig, sender)`` ``sig.send(sender)``
``dispatcher.connect(callback, sig, sender=Any)`` ``sig.connect(callback, sender=None)``
================================================= ======================================
Comments
--------
If you were using Django 0.96's ``django.contrib.comments`` app, you'll need to
upgrade to the new comments app introduced in 1.0. See
:doc:`/ref/contrib/comments/upgrade` for details.
Template tags
-------------
:ttag:`spaceless` tag
~~~~~~~~~~~~~~~~~~~~~
The spaceless template tag now removes *all* spaces between HTML tags, instead
of preserving a single space.
Local flavors
-------------
U.S. local flavor
~~~~~~~~~~~~~~~~~
``django.contrib.localflavor.usa`` has been renamed to
:mod:`django.contrib.localflavor.us`. This change was made to match the naming
scheme of other local flavors. To migrate your code, all you need to do is
change the imports.
Sessions
--------
Getting a new session key
~~~~~~~~~~~~~~~~~~~~~~~~~
``SessionBase.get_new_session_key()`` has been renamed to
``_get_new_session_key()``. ``get_new_session_object()`` no longer exists.
Fixtures
--------
Loading a row no longer calls ``save()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously, loading a row automatically ran the model's ``save()`` method. This
is no longer the case, so any fields (for example: timestamps) that were
auto-populated by a ``save()`` now need explicit values in any fixture.
Settings
--------
Better exceptions
~~~~~~~~~~~~~~~~~
The old :exc:`EnvironmentError` has split into an :exc:`ImportError` when
Django fails to find the settings module and a :exc:`RuntimeError` when you try
to reconfigure settings after having already used them
``LOGIN_URL`` has moved
~~~~~~~~~~~~~~~~~~~~~~~
The ``LOGIN_URL`` constant moved from ``django.contrib.auth`` into the
``settings`` module. Instead of using ``from django.contrib.auth import
LOGIN_URL`` refer to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
:setting:`APPEND_SLASH` behavior has been updated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In 0.96, if a URL didn't end in a slash or have a period in the final
component of its path, and ``APPEND_SLASH`` was True, Django would redirect
to the same URL, but with a slash appended to the end. Now, Django checks to
see whether the pattern without the trailing slash would be matched by
something in your URL patterns. If so, no redirection takes place, because it
is assumed you deliberately wanted to catch that pattern.
For most people, this won't require any changes. Some people, though, have URL
patterns that look like this::
r'/some_prefix/(.*)$'
Previously, those patterns would have been redirected to have a trailing
slash. If you always want a slash on such URLs, rewrite the pattern as::
r'/some_prefix/(.*/)$'
Smaller model changes
---------------------
Different exception from ``get()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Managers now return a :exc:`MultipleObjectsReturned` exception
instead of :exc:`AssertionError`:
Old (0.96)::
try:
Model.objects.get(...)
except AssertionError:
handle_the_error()
New (1.0)::
try:
Model.objects.get(...)
except Model.MultipleObjectsReturned:
handle_the_error()
``LazyDate`` has been fired
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``LazyDate`` helper class no longer exists.
Default field values and query arguments can both be callable objects, so
instances of ``LazyDate`` can be replaced with a reference to ``datetime.datetime.now``:
Old (0.96)::
class Article(models.Model):
title = models.CharField(maxlength=100)
published = models.DateField(default=LazyDate())
New (1.0)::
import datetime
class Article(models.Model):
title = models.CharField(max_length=100)
published = models.DateField(default=datetime.datetime.now)
``DecimalField`` is new, and ``FloatField`` is now a proper float
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Old (0.96)::
class MyModel(models.Model):
field_name = models.FloatField(max_digits=10, decimal_places=3)
...
New (1.0)::
class MyModel(models.Model):
field_name = models.DecimalField(max_digits=10, decimal_places=3)
...
If you forget to make this change, you will see errors about ``FloatField``
not taking a ``max_digits`` attribute in ``__init__``, because the new
``FloatField`` takes no precision-related arguments.
If you're using MySQL or PostgreSQL, no further changes are needed. The
database column types for ``DecimalField`` are the same as for the old
``FloatField``.
If you're using SQLite, you need to force the database to view the
appropriate columns as decimal types, rather than floats. To do this, you'll
need to reload your data. Do this after you have made the change to using
``DecimalField`` in your code and updated the Django code.
.. warning::
**Back up your database first!**
For SQLite, this means making a copy of the single file that stores the
database (the name of that file is the ``DATABASE_NAME`` in your settings.py
file).
To upgrade each application to use a ``DecimalField``, you can do the
following, replacing ``<app>`` in the code below with each app's name:
.. code-block:: bash
$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml
Notes:
1. It's important that you remember to use XML format in the first step of
this process. We are exploiting a feature of the XML data dumps that makes
porting floats to decimals with SQLite possible.
2. In the second step you will be asked to confirm that you are prepared to
lose the data for the application(s) in question. Say yes; we'll restore
this data in the third step, of course.
3. ``DecimalField`` is not used in any of the apps shipped with Django prior
to this change being made, so you do not need to worry about performing
this procedure for any of the standard Django models.
If something goes wrong in the above process, just copy your backed up
database file over the original file and start again.
Internationalization
--------------------
:func:`django.views.i18n.set_language` now requires a POST request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previously, a GET request was used. The old behavior meant that state (the
locale used to display the site) could be changed by a GET request, which is
against the HTTP specification's recommendations. Code calling this view must
ensure that a POST request is now made, instead of a GET. This means you can
no longer use a link to access the view, but must use a form submission of
some kind (e.g. a button).
``_()`` is no longer in builtins
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``_()`` (the callable object whose name is a single underscore) is no longer
monkeypatched into builtins -- that is, it's no longer available magically in
every module.
If you were previously relying on ``_()`` always being present, you should now
explicitly import ``ugettext`` or ``ugettext_lazy``, if appropriate, and alias
it to ``_`` yourself::
from django.utils.translation import ugettext as _
HTTP request/response objects
-----------------------------
Dictionary access to ``HttpRequest``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``HttpRequest`` objects no longer directly support dictionary-style
access; previously, both ``GET`` and ``POST`` data were directly
available on the ``HttpRequest`` object (e.g., you could check for a
piece of form data by using ``if 'some_form_key' in request`` or by
reading ``request['some_form_key']``. This is no longer supported; if
you need access to the combined ``GET`` and ``POST`` data, use
``request.REQUEST`` instead.
It is strongly suggested, however, that you always explicitly look in
the appropriate dictionary for the type of request you expect to
receive (``request.GET`` or ``request.POST``); relying on the combined
``request.REQUEST`` dictionary can mask the origin of incoming data.
Accessing ``HTTPResponse`` headers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``django.http.HttpResponse.headers`` has been renamed to ``_headers`` and
:class:`~django.http.HttpResponse` now supports containment checking directly.
So use ``if header in response:`` instead of ``if header in response.headers:``.
Generic relations
-----------------
Generic relations have been moved out of core
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The generic relation classes -- ``GenericForeignKey`` and ``GenericRelation``
-- have moved into the :mod:`django.contrib.contenttypes` module.
Testing
-------
:meth:`django.test.Client.login` has changed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Old (0.96)::
from django.test import Client
c = Client()
c.login('/path/to/login','myuser','mypassword')
New (1.0)::
# ... same as above, but then:
c.login(username='myuser', password='mypassword')
Management commands
-------------------
Running management commands from your code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:mod:`django.core.management` has been greatly refactored.
Calls to management services in your code now need to use
``call_command``. For example, if you have some test code that calls flush and
load_data::
from django.core import management
management.flush(verbosity=0, interactive=False)
management.load_data(['test_data'], verbosity=0)
...you'll need to change this code to read::
from django.core import management
management.call_command('flush', verbosity=0, interactive=False)
management.call_command('loaddata', 'test_data', verbosity=0)
Subcommands must now precede options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``django-admin.py`` and ``manage.py`` now require subcommands to precede
options. So:
.. code-block:: bash
$ django-admin.py --settings=foo.bar runserver
...no longer works and should be changed to:
.. code-block:: bash
$ django-admin.py runserver --settings=foo.bar
Syndication
-----------
``Feed.__init__`` has changed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``__init__()`` method of the syndication framework's ``Feed`` class now
takes an ``HttpRequest`` object as its second parameter, instead of the feed's
URL. This allows the syndication framework to work without requiring the sites
framework. This only affects code that subclasses ``Feed`` and overrides the
``__init__()`` method, and code that calls ``Feed.__init__()`` directly.
Data structures
---------------
``SortedDictFromList`` is gone
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``django.newforms.forms.SortedDictFromList`` was removed.
:class:`django.utils.datastructures.SortedDict` can now be instantiated with
a sequence of tuples.
To update your code:
1. Use :class:`django.utils.datastructures.SortedDict` wherever you were
using ``django.newforms.forms.SortedDictFromList``.
2. Because :meth:`django.utils.datastructures.SortedDict.copy` doesn't
return a deepcopy as ``SortedDictFromList.copy()`` did, you will need
to update your code if you were relying on a deepcopy. Do this by using
``copy.deepcopy`` directly.
Database backend functions
--------------------------
Database backend functions have been renamed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Almost *all* of the database backend-level functions have been renamed and/or
relocated. None of these were documented, but you'll need to change your code
if you're using any of these functions, all of which are in :mod:`django.db`:
======================================= ===================================================
Old (0.96) New (1.0)
======================================= ===================================================
``backend.get_autoinc_sql`` ``connection.ops.autoinc_sql``
``backend.get_date_extract_sql`` ``connection.ops.date_extract_sql``
``backend.get_date_trunc_sql`` ``connection.ops.date_trunc_sql``
``backend.get_datetime_cast_sql`` ``connection.ops.datetime_cast_sql``
``backend.get_deferrable_sql`` ``connection.ops.deferrable_sql``
``backend.get_drop_foreignkey_sql`` ``connection.ops.drop_foreignkey_sql``
``backend.get_fulltext_search_sql`` ``connection.ops.fulltext_search_sql``
``backend.get_last_insert_id`` ``connection.ops.last_insert_id``
``backend.get_limit_offset_sql`` ``connection.ops.limit_offset_sql``
``backend.get_max_name_length`` ``connection.ops.max_name_length``
``backend.get_pk_default_value`` ``connection.ops.pk_default_value``
``backend.get_random_function_sql`` ``connection.ops.random_function_sql``
``backend.get_sql_flush`` ``connection.ops.sql_flush``
``backend.get_sql_sequence_reset`` ``connection.ops.sequence_reset_sql``
``backend.get_start_transaction_sql`` ``connection.ops.start_transaction_sql``
``backend.get_tablespace_sql`` ``connection.ops.tablespace_sql``
``backend.quote_name`` ``connection.ops.quote_name``
``backend.get_query_set_class`` ``connection.ops.query_set_class``
``backend.get_field_cast_sql`` ``connection.ops.field_cast_sql``
``backend.get_drop_sequence`` ``connection.ops.drop_sequence_sql``
``backend.OPERATOR_MAPPING`` ``connection.operators``
``backend.allows_group_by_ordinal`` ``connection.features.allows_group_by_ordinal``
``backend.allows_unique_and_pk`` ``connection.features.allows_unique_and_pk``
``backend.autoindexes_primary_keys`` ``connection.features.autoindexes_primary_keys``
``backend.needs_datetime_string_cast`` ``connection.features.needs_datetime_string_cast``
``backend.needs_upper_for_iops`` ``connection.features.needs_upper_for_iops``
``backend.supports_constraints`` ``connection.features.supports_constraints``
``backend.supports_tablespaces`` ``connection.features.supports_tablespaces``
``backend.uses_case_insensitive_names`` ``connection.features.uses_case_insensitive_names``
``backend.uses_custom_queryset`` ``connection.features.uses_custom_queryset``
======================================= ===================================================
|