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