"Fossies" - the Fresh Open Source Software Archive

Member "Django-1.11.25/docs/releases/1.0-porting-guide.txt" (1 Oct 2019, 26674 Bytes) of package /linux/www/Django-1.11.25.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    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     __ https://www.djangosnippets.org/
   83     __ https://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     __ https://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
  281 :class:`~django.core.files.uploadedfile.UploadedFile`. The old dictionary
  282 syntax no longer works.
  283 
  284 Thus, in a view like::
  285 
  286       def my_view(request):
  287           f = request.FILES['file_field_name']
  288           ...
  289 
  290 ...you'd need to make the following changes:
  291 
  292 ===================== =====================
  293 Old (0.96)            New (1.0)
  294 ===================== =====================
  295 ``f['content']``      ``f.read()``
  296 ``f['filename']``     ``f.name``
  297 ``f['content-type']`` ``f.content_type``
  298 ===================== =====================
  299 
  300 Work with file fields using the new API
  301 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  302 
  303 The internal implementation of :class:`django.db.models.FileField` have changed.
  304 A visible result of this is that the way you access special attributes (URL,
  305 filename, image size, etc.) of these model fields has changed. You will need to
  306 make the following changes, assuming your model's
  307 :class:`~django.db.models.FileField` is called ``myfile``:
  308 
  309 =================================== ========================
  310 Old (0.96)                           New (1.0)
  311 =================================== ========================
  312 ``myfile.get_content_filename()``   ``myfile.content.path``
  313 ``myfile.get_content_url()``        ``myfile.content.url``
  314 ``myfile.get_content_size()``       ``myfile.content.size``
  315 ``myfile.save_content_file()``      ``myfile.content.save()``
  316 ``myfile.get_content_width()``      ``myfile.content.width``
  317 ``myfile.get_content_height()``     ``myfile.content.height``
  318 =================================== ========================
  319 
  320 Note that the ``width`` and ``height`` attributes only make sense for
  321 :class:`~django.db.models.ImageField` fields. More details can be found in the
  322 :doc:`model API </ref/models/fields>` documentation.
  323 
  324 Use ``Paginator`` instead of ``ObjectPaginator``
  325 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  326 
  327 The ``ObjectPaginator`` in 0.96 has been removed and replaced with an improved
  328 version, :class:`django.core.paginator.Paginator`.
  329 
  330 Templates
  331 ---------
  332 
  333 Learn to love autoescaping
  334 ~~~~~~~~~~~~~~~~~~~~~~~~~~
  335 
  336 By default, the template system now automatically HTML-escapes the output of
  337 every variable. To learn more, see :ref:`automatic-html-escaping`.
  338 
  339 To disable auto-escaping for an individual variable, use the :tfilter:`safe`
  340 filter:
  341 
  342 .. code-block:: html+django
  343 
  344       This will be escaped: {{ data }}
  345       This will not be escaped: {{ data|safe }}
  346 
  347 To disable auto-escaping for an entire template, wrap the template (or just a
  348 particular section of the template) in the :ttag:`autoescape` tag:
  349 
  350 .. code-block:: html+django
  351 
  352       {% autoescape off %}
  353          ... unescaped template content here ...
  354       {% endautoescape %}
  355 
  356 Less-common changes
  357 ===================
  358 
  359 The following changes are smaller, more localized changes. They should only
  360 affect more advanced users, but it's probably worth reading through the list and
  361 checking your code for these things.
  362 
  363 Signals
  364 -------
  365 
  366 * Add ``**kwargs`` to any registered signal handlers.
  367 
  368 * Connect, disconnect, and send signals via methods on the
  369   :class:`~django.dispatch.Signal` object instead of through module methods in
  370   ``django.dispatch.dispatcher``.
  371 
  372 * Remove any use of the ``Anonymous`` and ``Any`` sender options; they no longer
  373   exist. You can still receive signals sent by any sender by using
  374   ``sender=None``
  375 
  376 * Make any custom signals you've declared into instances of
  377   :class:`django.dispatch.Signal` instead of anonymous objects.
  378 
  379 Here's quick summary of the code changes you'll need to make:
  380 
  381 =================================================  ======================================
  382 Old (0.96)                                         New (1.0)
  383 =================================================  ======================================
  384 ``def callback(sender)``                           ``def callback(sender, **kwargs)``
  385 ``sig = object()``                                 ``sig = django.dispatch.Signal()``
  386 ``dispatcher.connect(callback, sig)``              ``sig.connect(callback)``
  387 ``dispatcher.send(sig, sender)``                   ``sig.send(sender)``
  388 ``dispatcher.connect(callback, sig, sender=Any)``  ``sig.connect(callback, sender=None)``
  389 =================================================  ======================================
  390 
  391 Comments
  392 --------
  393 
  394 If you were using Django 0.96's ``django.contrib.comments`` app, you'll need to
  395 upgrade to the new comments app introduced in 1.0. See the upgrade guide
  396 for details.
  397 
  398 Template tags
  399 -------------
  400 
  401 :ttag:`spaceless` tag
  402 ~~~~~~~~~~~~~~~~~~~~~
  403 
  404 The spaceless template tag now removes *all* spaces between HTML tags, instead
  405 of preserving a single space.
  406 
  407 Local flavors
  408 -------------
  409 
  410 U.S. local flavor
  411 ~~~~~~~~~~~~~~~~~
  412 
  413 ``django.contrib.localflavor.usa`` has been renamed to
  414 ``django.contrib.localflavor.us``. This change was made to match the naming
  415 scheme of other local flavors. To migrate your code, all you need to do is
  416 change the imports.
  417 
  418 Sessions
  419 --------
  420 
  421 Getting a new session key
  422 ~~~~~~~~~~~~~~~~~~~~~~~~~
  423 
  424 ``SessionBase.get_new_session_key()`` has been renamed to
  425 ``_get_new_session_key()``. ``get_new_session_object()`` no longer exists.
  426 
  427 Fixtures
  428 --------
  429 
  430 Loading a row no longer calls ``save()``
  431 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  432 
  433 Previously, loading a row automatically ran the model's ``save()`` method. This
  434 is no longer the case, so any fields (for example: timestamps) that were
  435 auto-populated by a ``save()`` now need explicit values in any fixture.
  436 
  437 Settings
  438 --------
  439 
  440 Better exceptions
  441 ~~~~~~~~~~~~~~~~~
  442 
  443 The old :exc:`EnvironmentError` has split into an
  444 :exc:`ImportError` when Django fails to find the settings module
  445 and a :exc:`RuntimeError` when you try to reconfigure settings
  446 after having already used them.
  447 
  448 :setting:`LOGIN_URL` has moved
  449 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  450 
  451 The :setting:`LOGIN_URL` constant moved from ``django.contrib.auth`` into the
  452 ``settings`` module. Instead of using ``from django.contrib.auth import
  453 LOGIN_URL`` refer to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
  454 
  455 :setting:`APPEND_SLASH` behavior has been updated
  456 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  457 
  458 In 0.96, if a URL didn't end in a slash or have a period in the final
  459 component of its path, and :setting:`APPEND_SLASH` was True, Django would
  460 redirect to the same URL, but with a slash appended to the end. Now, Django
  461 checks to see whether the pattern without the trailing slash would be matched
  462 by something in your URL patterns. If so, no redirection takes place, because
  463 it is assumed you deliberately wanted to catch that pattern.
  464 
  465 For most people, this won't require any changes. Some people, though, have URL
  466 patterns that look like this::
  467 
  468     r'/some_prefix/(.*)$'
  469 
  470 Previously, those patterns would have been redirected to have a trailing
  471 slash. If you always want a slash on such URLs, rewrite the pattern as::
  472 
  473     r'/some_prefix/(.*/)$'
  474 
  475 Smaller model changes
  476 ---------------------
  477 
  478 Different exception from ``get()``
  479 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  480 
  481 Managers now return a :exc:`~django.core.exceptions.MultipleObjectsReturned`
  482 exception instead of :exc:`AssertionError`:
  483 
  484 Old (0.96)::
  485 
  486     try:
  487         Model.objects.get(...)
  488     except AssertionError:
  489         handle_the_error()
  490 
  491 New (1.0)::
  492 
  493   try:
  494       Model.objects.get(...)
  495   except Model.MultipleObjectsReturned:
  496       handle_the_error()
  497 
  498 ``LazyDate`` has been fired
  499 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  500 
  501 The ``LazyDate`` helper class no longer exists.
  502 
  503 Default field values and query arguments can both be callable objects, so
  504 instances of ``LazyDate`` can be replaced with a reference to ``datetime.datetime.now``:
  505 
  506 Old (0.96)::
  507 
  508     class Article(models.Model):
  509         title = models.CharField(maxlength=100)
  510         published = models.DateField(default=LazyDate())
  511 
  512 New (1.0)::
  513 
  514     import datetime
  515 
  516     class Article(models.Model):
  517         title = models.CharField(max_length=100)
  518         published = models.DateField(default=datetime.datetime.now)
  519 
  520 ``DecimalField`` is new, and ``FloatField`` is now a proper float
  521 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  522 
  523 Old (0.96)::
  524 
  525     class MyModel(models.Model):
  526         field_name = models.FloatField(max_digits=10, decimal_places=3)
  527         ...
  528 
  529 New (1.0)::
  530 
  531     class MyModel(models.Model):
  532         field_name = models.DecimalField(max_digits=10, decimal_places=3)
  533         ...
  534 
  535 If you forget to make this change, you will see errors about ``FloatField``
  536 not taking a ``max_digits`` attribute in ``__init__``, because the new
  537 ``FloatField`` takes no precision-related arguments.
  538 
  539 If you're using MySQL or PostgreSQL, no further changes are needed. The
  540 database column types for ``DecimalField`` are the same as for the old
  541 ``FloatField``.
  542 
  543 If you're using SQLite, you need to force the database to view the
  544 appropriate columns as decimal types, rather than floats. To do this, you'll
  545 need to reload your data. Do this after you have made the change to using
  546 ``DecimalField`` in your code and updated the Django code.
  547 
  548 .. warning::
  549 
  550   **Back up your database first!**
  551 
  552   For SQLite, this means making a copy of the single file that stores the
  553   database (the name of that file is the ``DATABASE_NAME`` in your
  554   settings.py file).
  555 
  556 To upgrade each application to use a ``DecimalField``, you can do the
  557 following, replacing ``<app>`` in the code below with each app's name:
  558 
  559 .. code-block:: console
  560 
  561       $ ./manage.py dumpdata --format=xml <app> > data-dump.xml
  562       $ ./manage.py reset <app>
  563       $ ./manage.py loaddata data-dump.xml
  564 
  565 Notes:
  566 
  567 1. It's important that you remember to use XML format in the first step of
  568    this process. We are exploiting a feature of the XML data dumps that makes
  569    porting floats to decimals with SQLite possible.
  570 
  571 2. In the second step you will be asked to confirm that you are prepared to
  572    lose the data for the application(s) in question. Say yes; we'll restore
  573    this data in the third step, of course.
  574 
  575 3. ``DecimalField`` is not used in any of the apps shipped with Django prior
  576    to this change being made, so you do not need to worry about performing
  577    this procedure for any of the standard Django models.
  578 
  579 If something goes wrong in the above process, just copy your backed up
  580 database file over the original file and start again.
  581 
  582 Internationalization
  583 --------------------
  584 
  585 :func:`django.views.i18n.set_language` now requires a POST request
  586 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  587 
  588 Previously, a GET request was used. The old behavior meant that state (the
  589 locale used to display the site) could be changed by a GET request, which is
  590 against the HTTP specification's recommendations. Code calling this view must
  591 ensure that a POST request is now made, instead of a GET. This means you can
  592 no longer use a link to access the view, but must use a form submission of
  593 some kind (e.g. a button).
  594 
  595 ``_()`` is no longer in builtins
  596 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  597 
  598 ``_()`` (the callable object whose name is a single underscore) is no longer
  599 monkeypatched into builtins -- that is, it's no longer available magically in
  600 every module.
  601 
  602 If you were previously relying on ``_()`` always being present, you should now
  603 explicitly import ``ugettext`` or ``ugettext_lazy``, if appropriate, and alias
  604 it to ``_`` yourself::
  605 
  606     from django.utils.translation import ugettext as _
  607 
  608 HTTP request/response objects
  609 -----------------------------
  610 
  611 Dictionary access to ``HttpRequest``
  612 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  613 
  614 ``HttpRequest`` objects no longer directly support dictionary-style
  615 access; previously, both ``GET`` and ``POST`` data were directly
  616 available on the ``HttpRequest`` object (e.g., you could check for a
  617 piece of form data by using ``if 'some_form_key' in request`` or by
  618 reading ``request['some_form_key']``. This is no longer supported; if
  619 you need access to the combined ``GET`` and ``POST`` data, use
  620 ``request.REQUEST`` instead.
  621 
  622 It is strongly suggested, however, that you always explicitly look in
  623 the appropriate dictionary for the type of request you expect to
  624 receive (``request.GET`` or ``request.POST``); relying on the combined
  625 ``request.REQUEST`` dictionary can mask the origin of incoming data.
  626 
  627 Accessing ``HTTPResponse`` headers
  628 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  629 
  630 ``django.http.HttpResponse.headers`` has been renamed to ``_headers`` and
  631 :class:`~django.http.HttpResponse` now supports containment checking directly.
  632 So use ``if header in response:`` instead of ``if header in response.headers:``.
  633 
  634 Generic relations
  635 -----------------
  636 
  637 Generic relations have been moved out of core
  638 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  639 
  640 The generic relation classes -- ``GenericForeignKey`` and ``GenericRelation``
  641 -- have moved into the :mod:`django.contrib.contenttypes` module.
  642 
  643 Testing
  644 -------
  645 
  646 :meth:`django.test.Client.login` has changed
  647 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  648 
  649 Old (0.96)::
  650 
  651     from django.test import Client
  652     c = Client()
  653     c.login('/path/to/login','myuser','mypassword')
  654 
  655 New (1.0)::
  656 
  657     # ... same as above, but then:
  658     c.login(username='myuser', password='mypassword')
  659 
  660 Management commands
  661 -------------------
  662 
  663 Running management commands from your code
  664 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  665 
  666 :mod:`django.core.management` has been greatly refactored.
  667 
  668 Calls to management services in your code now need to use
  669 ``call_command``. For example, if you have some test code that calls flush and
  670 load_data::
  671 
  672       from django.core import management
  673       management.flush(verbosity=0, interactive=False)
  674       management.load_data(['test_data'], verbosity=0)
  675 
  676 ...you'll need to change this code to read::
  677 
  678       from django.core import management
  679       management.call_command('flush', verbosity=0, interactive=False)
  680       management.call_command('loaddata', 'test_data', verbosity=0)
  681 
  682 Subcommands must now precede options
  683 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  684 
  685 ``django-admin.py`` and ``manage.py`` now require subcommands to precede
  686 options. So:
  687 
  688 .. code-block:: console
  689 
  690       $ django-admin.py --settings=foo.bar runserver
  691 
  692 ...no longer works and should be changed to:
  693 
  694 .. code-block:: console
  695 
  696       $ django-admin.py runserver --settings=foo.bar
  697 
  698 Syndication
  699 -----------
  700 
  701 ``Feed.__init__`` has changed
  702 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  703 
  704 The ``__init__()`` method of the syndication framework's ``Feed`` class now
  705 takes an ``HttpRequest`` object as its second parameter, instead of the feed's
  706 URL. This allows the syndication framework to work without requiring the sites
  707 framework. This only affects code that subclasses ``Feed`` and overrides the
  708 ``__init__()`` method, and code that calls ``Feed.__init__()`` directly.
  709 
  710 Data structures
  711 ---------------
  712 
  713 ``SortedDictFromList`` is gone
  714 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  715 
  716 ``django.newforms.forms.SortedDictFromList`` was removed.
  717 ``django.utils.datastructures.SortedDict`` can now be instantiated with
  718 a sequence of tuples.
  719 
  720 To update your code:
  721 
  722 1. Use ``django.utils.datastructures.SortedDict`` wherever you were
  723    using ``django.newforms.forms.SortedDictFromList``.
  724 
  725 2. Because ``django.utils.datastructures.SortedDict.copy`` doesn't
  726    return a deepcopy as ``SortedDictFromList.copy()`` did, you will need
  727    to update your code if you were relying on a deepcopy. Do this by using
  728    ``copy.deepcopy`` directly.
  729 
  730 Database backend functions
  731 --------------------------
  732 
  733 Database backend functions have been renamed
  734 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  735 
  736 Almost *all* of the database backend-level functions have been renamed and/or
  737 relocated. None of these were documented, but you'll need to change your code
  738 if you're using any of these functions, all of which are in :mod:`django.db`:
  739 
  740 =======================================  ===================================================
  741 Old (0.96)                               New (1.0)
  742 =======================================  ===================================================
  743 ``backend.get_autoinc_sql``              ``connection.ops.autoinc_sql``
  744 ``backend.get_date_extract_sql``         ``connection.ops.date_extract_sql``
  745 ``backend.get_date_trunc_sql``           ``connection.ops.date_trunc_sql``
  746 ``backend.get_datetime_cast_sql``        ``connection.ops.datetime_cast_sql``
  747 ``backend.get_deferrable_sql``           ``connection.ops.deferrable_sql``
  748 ``backend.get_drop_foreignkey_sql``      ``connection.ops.drop_foreignkey_sql``
  749 ``backend.get_fulltext_search_sql``      ``connection.ops.fulltext_search_sql``
  750 ``backend.get_last_insert_id``           ``connection.ops.last_insert_id``
  751 ``backend.get_limit_offset_sql``         ``connection.ops.limit_offset_sql``
  752 ``backend.get_max_name_length``          ``connection.ops.max_name_length``
  753 ``backend.get_pk_default_value``         ``connection.ops.pk_default_value``
  754 ``backend.get_random_function_sql``      ``connection.ops.random_function_sql``
  755 ``backend.get_sql_flush``                ``connection.ops.sql_flush``
  756 ``backend.get_sql_sequence_reset``       ``connection.ops.sequence_reset_sql``
  757 ``backend.get_start_transaction_sql``    ``connection.ops.start_transaction_sql``
  758 ``backend.get_tablespace_sql``           ``connection.ops.tablespace_sql``
  759 ``backend.quote_name``                   ``connection.ops.quote_name``
  760 ``backend.get_query_set_class``          ``connection.ops.query_set_class``
  761 ``backend.get_field_cast_sql``           ``connection.ops.field_cast_sql``
  762 ``backend.get_drop_sequence``            ``connection.ops.drop_sequence_sql``
  763 ``backend.OPERATOR_MAPPING``             ``connection.operators``
  764 ``backend.allows_group_by_ordinal``      ``connection.features.allows_group_by_ordinal``
  765 ``backend.allows_unique_and_pk``         ``connection.features.allows_unique_and_pk``
  766 ``backend.autoindexes_primary_keys``     ``connection.features.autoindexes_primary_keys``
  767 ``backend.needs_datetime_string_cast``   ``connection.features.needs_datetime_string_cast``
  768 ``backend.needs_upper_for_iops``         ``connection.features.needs_upper_for_iops``
  769 ``backend.supports_constraints``         ``connection.features.supports_constraints``
  770 ``backend.supports_tablespaces``         ``connection.features.supports_tablespaces``
  771 ``backend.uses_case_insensitive_names``  ``connection.features.uses_case_insensitive_names``
  772 ``backend.uses_custom_queryset``         ``connection.features.uses_custom_queryset``
  773 =======================================  ===================================================