1.0-porting-guide.txt 26 KB

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