1.0-porting-guide.txt 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  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. __ https://www.djangosnippets.org/
  58. __ https://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. __ https://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
  190. :class:`~django.core.files.uploadedfile.UploadedFile`. The old dictionary
  191. syntax no longer works.
  192. Thus, in a view like::
  193. def my_view(request):
  194. f = request.FILES['file_field_name']
  195. ...
  196. ...you'd need to make the following changes:
  197. ===================== =====================
  198. Old (0.96) New (1.0)
  199. ===================== =====================
  200. ``f['content']`` ``f.read()``
  201. ``f['filename']`` ``f.name``
  202. ``f['content-type']`` ``f.content_type``
  203. ===================== =====================
  204. Work with file fields using the new API
  205. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  206. The internal implementation of :class:`django.db.models.FileField` have changed.
  207. A visible result of this is that the way you access special attributes (URL,
  208. filename, image size, etc.) of these model fields has changed. You will need to
  209. make the following changes, assuming your model's
  210. :class:`~django.db.models.FileField` is called ``myfile``:
  211. =================================== ========================
  212. Old (0.96) New (1.0)
  213. =================================== ========================
  214. ``myfile.get_content_filename()`` ``myfile.content.path``
  215. ``myfile.get_content_url()`` ``myfile.content.url``
  216. ``myfile.get_content_size()`` ``myfile.content.size``
  217. ``myfile.save_content_file()`` ``myfile.content.save()``
  218. ``myfile.get_content_width()`` ``myfile.content.width``
  219. ``myfile.get_content_height()`` ``myfile.content.height``
  220. =================================== ========================
  221. Note that the ``width`` and ``height`` attributes only make sense for
  222. :class:`~django.db.models.ImageField` fields. More details can be found in the
  223. :doc:`model API </ref/models/fields>` documentation.
  224. Use ``Paginator`` instead of ``ObjectPaginator``
  225. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  226. The ``ObjectPaginator`` in 0.96 has been removed and replaced with an improved
  227. version, :class:`django.core.paginator.Paginator`.
  228. Templates
  229. ---------
  230. Learn to love autoescaping
  231. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  232. By default, the template system now automatically HTML-escapes the output of
  233. every variable. To learn more, see :ref:`automatic-html-escaping`.
  234. To disable auto-escaping for an individual variable, use the :tfilter:`safe`
  235. filter:
  236. .. code-block:: html+django
  237. This will be escaped: {{ data }}
  238. This will not be escaped: {{ data|safe }}
  239. To disable auto-escaping for an entire template, wrap the template (or just a
  240. particular section of the template) in the :ttag:`autoescape` tag:
  241. .. code-block:: html+django
  242. {% autoescape off %}
  243. ... unescaped template content here ...
  244. {% endautoescape %}
  245. Less-common changes
  246. ===================
  247. The following changes are smaller, more localized changes. They should only
  248. affect more advanced users, but it's probably worth reading through the list and
  249. checking your code for these things.
  250. Signals
  251. -------
  252. * Add ``**kwargs`` to any registered signal handlers.
  253. * Connect, disconnect, and send signals via methods on the
  254. :class:`~django.dispatch.Signal` object instead of through module methods in
  255. ``django.dispatch.dispatcher``.
  256. * Remove any use of the ``Anonymous`` and ``Any`` sender options; they no longer
  257. exist. You can still receive signals sent by any sender by using
  258. ``sender=None``
  259. * Make any custom signals you've declared into instances of
  260. :class:`django.dispatch.Signal` instead of anonymous objects.
  261. Here's quick summary of the code changes you'll need to make:
  262. ================================================= ======================================
  263. Old (0.96) New (1.0)
  264. ================================================= ======================================
  265. ``def callback(sender)`` ``def callback(sender, **kwargs)``
  266. ``sig = object()`` ``sig = django.dispatch.Signal()``
  267. ``dispatcher.connect(callback, sig)`` ``sig.connect(callback)``
  268. ``dispatcher.send(sig, sender)`` ``sig.send(sender)``
  269. ``dispatcher.connect(callback, sig, sender=Any)`` ``sig.connect(callback, sender=None)``
  270. ================================================= ======================================
  271. Comments
  272. --------
  273. If you were using Django 0.96's ``django.contrib.comments`` app, you'll need to
  274. upgrade to the new comments app introduced in 1.0. See the upgrade guide
  275. for details.
  276. Template tags
  277. -------------
  278. :ttag:`spaceless` tag
  279. ~~~~~~~~~~~~~~~~~~~~~
  280. The ``spaceless`` template tag now removes *all* spaces between HTML tags,
  281. instead of preserving a single space.
  282. Local flavors
  283. -------------
  284. U.S. local flavor
  285. ~~~~~~~~~~~~~~~~~
  286. ``django.contrib.localflavor.usa`` has been renamed to
  287. ``django.contrib.localflavor.us``. This change was made to match the naming
  288. scheme of other local flavors. To migrate your code, all you need to do is
  289. change the imports.
  290. Sessions
  291. --------
  292. Getting a new session key
  293. ~~~~~~~~~~~~~~~~~~~~~~~~~
  294. ``SessionBase.get_new_session_key()`` has been renamed to
  295. ``_get_new_session_key()``. ``get_new_session_object()`` no longer exists.
  296. Fixtures
  297. --------
  298. Loading a row no longer calls ``save()``
  299. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  300. Previously, loading a row automatically ran the model's ``save()`` method. This
  301. is no longer the case, so any fields (for example: timestamps) that were
  302. auto-populated by a ``save()`` now need explicit values in any fixture.
  303. Settings
  304. --------
  305. Better exceptions
  306. ~~~~~~~~~~~~~~~~~
  307. The old :exc:`EnvironmentError` has split into an
  308. :exc:`ImportError` when Django fails to find the settings module
  309. and a :exc:`RuntimeError` when you try to reconfigure settings
  310. after having already used them.
  311. :setting:`LOGIN_URL` has moved
  312. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  313. The :setting:`LOGIN_URL` constant moved from ``django.contrib.auth`` into the
  314. ``settings`` module. Instead of using ``from django.contrib.auth import
  315. LOGIN_URL`` refer to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
  316. :setting:`APPEND_SLASH` behavior has been updated
  317. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  318. In 0.96, if a URL didn't end in a slash or have a period in the final
  319. component of its path, and :setting:`APPEND_SLASH` was True, Django would
  320. redirect to the same URL, but with a slash appended to the end. Now, Django
  321. checks to see whether the pattern without the trailing slash would be matched
  322. by something in your URL patterns. If so, no redirection takes place, because
  323. it is assumed you deliberately wanted to catch that pattern.
  324. For most people, this won't require any changes. Some people, though, have URL
  325. patterns that look like this::
  326. r'/some_prefix/(.*)$'
  327. Previously, those patterns would have been redirected to have a trailing
  328. slash. If you always want a slash on such URLs, rewrite the pattern as::
  329. r'/some_prefix/(.*/)$'
  330. Smaller model changes
  331. ---------------------
  332. Different exception from ``get()``
  333. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  334. Managers now return a :exc:`~django.core.exceptions.MultipleObjectsReturned`
  335. exception instead of :exc:`AssertionError`:
  336. Old (0.96)::
  337. try:
  338. Model.objects.get(...)
  339. except AssertionError:
  340. handle_the_error()
  341. New (1.0)::
  342. try:
  343. Model.objects.get(...)
  344. except Model.MultipleObjectsReturned:
  345. handle_the_error()
  346. ``LazyDate`` has been fired
  347. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  348. The ``LazyDate`` helper class no longer exists.
  349. Default field values and query arguments can both be callable objects, so
  350. instances of ``LazyDate`` can be replaced with a reference to ``datetime.datetime.now``:
  351. Old (0.96)::
  352. class Article(models.Model):
  353. title = models.CharField(maxlength=100)
  354. published = models.DateField(default=LazyDate())
  355. New (1.0)::
  356. import datetime
  357. class Article(models.Model):
  358. title = models.CharField(max_length=100)
  359. published = models.DateField(default=datetime.datetime.now)
  360. ``DecimalField`` is new, and ``FloatField`` is now a proper float
  361. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  362. Old (0.96)::
  363. class MyModel(models.Model):
  364. field_name = models.FloatField(max_digits=10, decimal_places=3)
  365. ...
  366. New (1.0)::
  367. class MyModel(models.Model):
  368. field_name = models.DecimalField(max_digits=10, decimal_places=3)
  369. ...
  370. If you forget to make this change, you will see errors about ``FloatField``
  371. not taking a ``max_digits`` attribute in ``__init__``, because the new
  372. ``FloatField`` takes no precision-related arguments.
  373. If you're using MySQL or PostgreSQL, no further changes are needed. The
  374. database column types for ``DecimalField`` are the same as for the old
  375. ``FloatField``.
  376. If you're using SQLite, you need to force the database to view the
  377. appropriate columns as decimal types, rather than floats. To do this, you'll
  378. need to reload your data. Do this after you have made the change to using
  379. ``DecimalField`` in your code and updated the Django code.
  380. .. warning::
  381. **Back up your database first!**
  382. For SQLite, this means making a copy of the single file that stores the
  383. database (the name of that file is the ``DATABASE_NAME`` in your
  384. settings.py file).
  385. To upgrade each application to use a ``DecimalField``, you can do the
  386. following, replacing ``<app>`` in the code below with each app's name:
  387. .. code-block:: console
  388. $ ./manage.py dumpdata --format=xml <app> > data-dump.xml
  389. $ ./manage.py reset <app>
  390. $ ./manage.py loaddata data-dump.xml
  391. Notes:
  392. 1. It's important that you remember to use XML format in the first step of
  393. this process. We are exploiting a feature of the XML data dumps that makes
  394. porting floats to decimals with SQLite possible.
  395. 2. In the second step you will be asked to confirm that you are prepared to
  396. lose the data for the application(s) in question. Say yes; we'll restore
  397. this data in the third step, of course.
  398. 3. ``DecimalField`` is not used in any of the apps shipped with Django prior
  399. to this change being made, so you do not need to worry about performing
  400. this procedure for any of the standard Django models.
  401. If something goes wrong in the above process, just copy your backed up
  402. database file over the original file and start again.
  403. Internationalization
  404. --------------------
  405. :func:`django.views.i18n.set_language` now requires a POST request
  406. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  407. Previously, a GET request was used. The old behavior meant that state (the
  408. locale used to display the site) could be changed by a GET request, which is
  409. against the HTTP specification's recommendations. Code calling this view must
  410. ensure that a POST request is now made, instead of a GET. This means you can
  411. no longer use a link to access the view, but must use a form submission of
  412. some kind (e.g. a button).
  413. ``_()`` is no longer in builtins
  414. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  415. ``_()`` (the callable object whose name is a single underscore) is no longer
  416. monkeypatched into builtins -- that is, it's no longer available magically in
  417. every module.
  418. If you were previously relying on ``_()`` always being present, you should now
  419. explicitly import ``ugettext`` or ``ugettext_lazy``, if appropriate, and alias
  420. it to ``_`` yourself::
  421. from django.utils.translation import ugettext as _
  422. HTTP request/response objects
  423. -----------------------------
  424. Dictionary access to ``HttpRequest``
  425. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  426. ``HttpRequest`` objects no longer directly support dictionary-style
  427. access; previously, both ``GET`` and ``POST`` data were directly
  428. available on the ``HttpRequest`` object (e.g., you could check for a
  429. piece of form data by using ``if 'some_form_key' in request`` or by
  430. reading ``request['some_form_key']``. This is no longer supported; if
  431. you need access to the combined ``GET`` and ``POST`` data, use
  432. ``request.REQUEST`` instead.
  433. It is strongly suggested, however, that you always explicitly look in
  434. the appropriate dictionary for the type of request you expect to
  435. receive (``request.GET`` or ``request.POST``); relying on the combined
  436. ``request.REQUEST`` dictionary can mask the origin of incoming data.
  437. Accessing ``HTTPResponse`` headers
  438. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  439. ``django.http.HttpResponse.headers`` has been renamed to ``_headers`` and
  440. :class:`~django.http.HttpResponse` now supports containment checking directly.
  441. So use ``if header in response:`` instead of ``if header in response.headers:``.
  442. Generic relations
  443. -----------------
  444. Generic relations have been moved out of core
  445. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  446. The generic relation classes -- ``GenericForeignKey`` and ``GenericRelation``
  447. -- have moved into the :mod:`django.contrib.contenttypes` module.
  448. Testing
  449. -------
  450. :meth:`django.test.Client.login` has changed
  451. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  452. Old (0.96)::
  453. from django.test import Client
  454. c = Client()
  455. c.login('/path/to/login','myuser','mypassword')
  456. New (1.0)::
  457. # ... same as above, but then:
  458. c.login(username='myuser', password='mypassword')
  459. Management commands
  460. -------------------
  461. Running management commands from your code
  462. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  463. :mod:`django.core.management` has been greatly refactored.
  464. Calls to management services in your code now need to use
  465. ``call_command``. For example, if you have some test code that calls flush and
  466. load_data::
  467. from django.core import management
  468. management.flush(verbosity=0, interactive=False)
  469. management.load_data(['test_data'], verbosity=0)
  470. ...you'll need to change this code to read::
  471. from django.core import management
  472. management.call_command('flush', verbosity=0, interactive=False)
  473. management.call_command('loaddata', 'test_data', verbosity=0)
  474. Subcommands must now precede options
  475. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  476. ``django-admin.py`` and ``manage.py`` now require subcommands to precede
  477. options. So:
  478. .. code-block:: console
  479. $ django-admin.py --settings=foo.bar runserver
  480. ...no longer works and should be changed to:
  481. .. code-block:: console
  482. $ django-admin.py runserver --settings=foo.bar
  483. Syndication
  484. -----------
  485. ``Feed.__init__`` has changed
  486. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  487. The ``__init__()`` method of the syndication framework's ``Feed`` class now
  488. takes an ``HttpRequest`` object as its second parameter, instead of the feed's
  489. URL. This allows the syndication framework to work without requiring the sites
  490. framework. This only affects code that subclasses ``Feed`` and overrides the
  491. ``__init__()`` method, and code that calls ``Feed.__init__()`` directly.
  492. Data structures
  493. ---------------
  494. ``SortedDictFromList`` is gone
  495. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  496. ``django.newforms.forms.SortedDictFromList`` was removed.
  497. ``django.utils.datastructures.SortedDict`` can now be instantiated with
  498. a sequence of tuples.
  499. To update your code:
  500. 1. Use ``django.utils.datastructures.SortedDict`` wherever you were
  501. using ``django.newforms.forms.SortedDictFromList``.
  502. 2. Because ``django.utils.datastructures.SortedDict.copy`` doesn't
  503. return a deepcopy as ``SortedDictFromList.copy()`` did, you will need
  504. to update your code if you were relying on a deepcopy. Do this by using
  505. ``copy.deepcopy`` directly.
  506. Database backend functions
  507. --------------------------
  508. Database backend functions have been renamed
  509. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  510. Almost *all* of the database backend-level functions have been renamed and/or
  511. relocated. None of these were documented, but you'll need to change your code
  512. if you're using any of these functions, all of which are in :mod:`django.db`:
  513. ======================================= ===================================================
  514. Old (0.96) New (1.0)
  515. ======================================= ===================================================
  516. ``backend.get_autoinc_sql`` ``connection.ops.autoinc_sql``
  517. ``backend.get_date_extract_sql`` ``connection.ops.date_extract_sql``
  518. ``backend.get_date_trunc_sql`` ``connection.ops.date_trunc_sql``
  519. ``backend.get_datetime_cast_sql`` ``connection.ops.datetime_cast_sql``
  520. ``backend.get_deferrable_sql`` ``connection.ops.deferrable_sql``
  521. ``backend.get_drop_foreignkey_sql`` ``connection.ops.drop_foreignkey_sql``
  522. ``backend.get_fulltext_search_sql`` ``connection.ops.fulltext_search_sql``
  523. ``backend.get_last_insert_id`` ``connection.ops.last_insert_id``
  524. ``backend.get_limit_offset_sql`` ``connection.ops.limit_offset_sql``
  525. ``backend.get_max_name_length`` ``connection.ops.max_name_length``
  526. ``backend.get_pk_default_value`` ``connection.ops.pk_default_value``
  527. ``backend.get_random_function_sql`` ``connection.ops.random_function_sql``
  528. ``backend.get_sql_flush`` ``connection.ops.sql_flush``
  529. ``backend.get_sql_sequence_reset`` ``connection.ops.sequence_reset_sql``
  530. ``backend.get_start_transaction_sql`` ``connection.ops.start_transaction_sql``
  531. ``backend.get_tablespace_sql`` ``connection.ops.tablespace_sql``
  532. ``backend.quote_name`` ``connection.ops.quote_name``
  533. ``backend.get_query_set_class`` ``connection.ops.query_set_class``
  534. ``backend.get_field_cast_sql`` ``connection.ops.field_cast_sql``
  535. ``backend.get_drop_sequence`` ``connection.ops.drop_sequence_sql``
  536. ``backend.OPERATOR_MAPPING`` ``connection.operators``
  537. ``backend.allows_group_by_ordinal`` ``connection.features.allows_group_by_ordinal``
  538. ``backend.allows_unique_and_pk`` ``connection.features.allows_unique_and_pk``
  539. ``backend.autoindexes_primary_keys`` ``connection.features.autoindexes_primary_keys``
  540. ``backend.needs_datetime_string_cast`` ``connection.features.needs_datetime_string_cast``
  541. ``backend.needs_upper_for_iops`` ``connection.features.needs_upper_for_iops``
  542. ``backend.supports_constraints`` ``connection.features.supports_constraints``
  543. ``backend.supports_tablespaces`` ``connection.features.supports_tablespaces``
  544. ``backend.uses_case_insensitive_names`` ``connection.features.uses_case_insensitive_names``
  545. ``backend.uses_custom_queryset`` ``connection.features.uses_custom_queryset``
  546. ======================================= ===================================================