123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- =========================================
- 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`__.
- __ https://www.djangosnippets.org/
- __ https://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>`.
- __ https://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.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 the upgrade guide
- 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
- ``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.
- :setting:`LOGIN_URL` has moved
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The :setting:`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 :setting:`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:`~django.core.exceptions.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:: console
- $ ./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:: console
- $ django-admin.py --settings=foo.bar runserver
- ...no longer works and should be changed to:
- .. code-block:: console
- $ 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.
- ``django.utils.datastructures.SortedDict`` can now be instantiated with
- a sequence of tuples.
- To update your code:
- 1. Use ``django.utils.datastructures.SortedDict`` wherever you were
- using ``django.newforms.forms.SortedDictFromList``.
- 2. Because ``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``
- ======================================= ===================================================
|