diff options
Diffstat (limited to 'docs')
91 files changed, 2031 insertions, 688 deletions
diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py index 3ae770da20..833232a0c3 100644 --- a/docs/_ext/djangodocs.py +++ b/docs/_ext/djangodocs.py @@ -137,7 +137,7 @@ class DjangoHTMLTranslator(SmartyPantsHTMLTranslator): ) title = "%s%s" % ( self.version_text[node['type']] % node['version'], - len(node) and ":" or "." + ":" if len(node) else "." ) self.body.append('<span class="title">%s</span> ' % title) diff --git a/docs/conf.py b/docs/conf.py index a654e3c4d6..a01ddb60b8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -109,7 +109,7 @@ pygments_style = 'trac' intersphinx_mapping = { 'python': ('http://docs.python.org/2.7', None), 'sphinx': ('http://sphinx.pocoo.org/', None), - 'six': ('http://packages.python.org/six/', None), + 'six': ('http://pythonhosted.org/six/', None), 'simplejson': ('http://simplejson.readthedocs.org/en/latest/', None), } diff --git a/docs/faq/admin.txt b/docs/faq/admin.txt index 1d9a7c7427..ec40754094 100644 --- a/docs/faq/admin.txt +++ b/docs/faq/admin.txt @@ -27,12 +27,6 @@ account has :attr:`~django.contrib.auth.models.User.is_active` and :attr:`~django.contrib.auth.models.User.is_staff` set to True. The admin site only allows access to users with those two fields both set to True. -How can I prevent the cache middleware from caching the admin site? -------------------------------------------------------------------- - -Set the :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY` setting to ``True``. See the -:doc:`cache documentation </topics/cache>` for more information. - How do I automatically set a field's value to the user who last edited the object in the admin? ----------------------------------------------------------------------------------------------- diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt index 0d35654a04..35f78718e4 100644 --- a/docs/howto/custom-template-tags.txt +++ b/docs/howto/custom-template-tags.txt @@ -20,7 +20,8 @@ create a new app to hold them. The app should contain a ``templatetags`` directory, at the same level as ``models.py``, ``views.py``, etc. If this doesn't already exist, create it - don't forget the ``__init__.py`` file to ensure the directory is treated as a -Python package. +Python package. After adding this module, you will need to restart your server +before you can use the tags or filters in templates. Your custom tags and filters will live in a module inside the ``templatetags`` directory. The name of the module file is the name you'll use to load the tags @@ -72,6 +73,8 @@ following: For more information on the :ttag:`load` tag, read its documentation. +.. _howto-writing-custom-template-filters: + Writing custom template filters ------------------------------- @@ -300,18 +303,21 @@ Template filter code falls into one of two situations: .. code-block:: python - from django.utils.html import conditional_escape - from django.utils.safestring import mark_safe + from django import template + from django.utils.html import conditional_escape + from django.utils.safestring import mark_safe + + register = template.Library() - @register.filter(needs_autoescape=True) - def initial_letter_filter(text, autoescape=None): - first, other = text[0], text[1:] - if autoescape: - esc = conditional_escape - else: - esc = lambda x: x - result = '<strong>%s</strong>%s' % (esc(first), esc(other)) - return mark_safe(result) + @register.filter(needs_autoescape=True) + def initial_letter_filter(text, autoescape=None): + first, other = text[0], text[1:] + if autoescape: + esc = conditional_escape + else: + esc = lambda x: x + result = '<strong>%s</strong>%s' % (esc(first), esc(other)) + return mark_safe(result) The ``needs_autoescape`` flag and the ``autoescape`` keyword argument mean that our function will know whether automatic escaping is in effect when the @@ -454,8 +460,9 @@ Continuing the above example, we need to define ``CurrentTimeNode``: .. code-block:: python - from django import template import datetime + from django import template + class CurrentTimeNode(template.Node): def __init__(self, format_string): self.format_string = format_string @@ -498,6 +505,8 @@ The ``__init__`` method for the ``Context`` class takes a parameter called .. code-block:: python + from django.template import Context + def render(self, context): # ... new_context = Context({'var': obj}, autoescape=context.autoescape) @@ -545,7 +554,10 @@ A naive implementation of ``CycleNode`` might look something like this: .. code-block:: python - class CycleNode(Node): + import itertools + from django import template + + class CycleNode(template.Node): def __init__(self, cyclevars): self.cycle_iter = itertools.cycle(cyclevars) def render(self, context): @@ -576,7 +588,7 @@ Let's refactor our ``CycleNode`` implementation to use the ``render_context``: .. code-block:: python - class CycleNode(Node): + class CycleNode(template.Node): def __init__(self, cyclevars): self.cyclevars = cyclevars def render(self, context): @@ -664,6 +676,7 @@ Now your tag should begin to look like this: .. code-block:: python from django import template + def do_format_time(parser, token): try: # split_contents() knows not to split quoted strings. @@ -722,6 +735,11 @@ Our earlier ``current_time`` function could thus be written like this: .. code-block:: python + import datetime + from django import template + + register = template.Library() + def current_time(format_string): return datetime.datetime.now().strftime(format_string) @@ -965,6 +983,9 @@ outputting it: .. code-block:: python + import datetime + from django import template + class CurrentTimeNode2(template.Node): def __init__(self, format_string): self.format_string = format_string diff --git a/docs/howto/deployment/checklist.txt b/docs/howto/deployment/checklist.txt index b72be75497..1a235673e8 100644 --- a/docs/howto/deployment/checklist.txt +++ b/docs/howto/deployment/checklist.txt @@ -160,9 +160,10 @@ only useful in development. In addition, you can tune the following settings. :setting:`CONN_MAX_AGE` ----------------------- -Enabling `persistent database connections <persistent-database-connections>`_ -can result in a nice speed-up when connecting to the database accounts for a -significant part of the request processing time. +Enabling :ref:`persistent database connections +<persistent-database-connections>` can result in a nice speed-up when +connecting to the database accounts for a significant part of the request +processing time. This helps a lot on virtualized hosts with limited network performance. @@ -212,3 +213,18 @@ Miscellaneous -------------------------------- This setting is required if you're using the :ttag:`ssi` template tag. + +Python Options +============== + +If you're using Python 2.6.8+, it's strongly recommended that you invoke the +Python process running your Django application using the `-R`_ option or with +the :envvar:`PYTHONHASHSEED` environment variable set to ``random``. + +These options help protect your site from denial-of-service (DoS) +attacks triggered by carefully crafted inputs. Such an attack can +drastically increase CPU usage by causing worst-case performance when +creating ``dict`` instances. See `oCERT advisory #2011-003 +<http://www.ocert.org/advisories/ocert-2011-003.html>`_ for more information. + +.. _-r: http://docs.python.org/2.7/using/cmdline.html#cmdoption-R diff --git a/docs/howto/deployment/wsgi/uwsgi.txt b/docs/howto/deployment/wsgi/uwsgi.txt index 5b40d5f2f7..22f39342d6 100644 --- a/docs/howto/deployment/wsgi/uwsgi.txt +++ b/docs/howto/deployment/wsgi/uwsgi.txt @@ -62,7 +62,6 @@ Here's an example command to start a uWSGI server:: --processes=5 \ # number of worker processes --uid=1000 --gid=2000 \ # if root, uwsgi can drop privileges --harakiri=20 \ # respawn processes taking more than 20 seconds - --limit-as=128 \ # limit the project to 128 MB --max-requests=5000 \ # respawn processes after serving 5000 requests --vacuum \ # clear environment on exit --home=/path/to/virtual/env \ # optional path to a virtualenv diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt index 27f11f4936..987a503e95 100644 --- a/docs/howto/error-reporting.txt +++ b/docs/howto/error-reporting.txt @@ -98,6 +98,11 @@ crawlers often request:: (Note that these are regular expressions, so we put a backslash in front of periods to escape them.) +If you'd like to customize the behavior of +:class:`django.middleware.common.BrokenLinkEmailsMiddleware` further (for +example to ignore requests coming from web crawlers), you should subclass it +and override its methods. + .. seealso:: 404 errors are logged using the logging framework. By default, these log diff --git a/docs/howto/index.txt b/docs/howto/index.txt index 9d5b067a82..fe25c11756 100644 --- a/docs/howto/index.txt +++ b/docs/howto/index.txt @@ -15,6 +15,7 @@ you quickly accomplish common tasks. custom-template-tags custom-file-storage deployment/index + upgrade-version error-reporting initial-data jython diff --git a/docs/howto/static-files/index.txt b/docs/howto/static-files/index.txt index 1fdad94143..3668c5dc41 100644 --- a/docs/howto/static-files/index.txt +++ b/docs/howto/static-files/index.txt @@ -35,8 +35,20 @@ Configuring static files 4. Store your static files in a folder called ``static`` in your app. For example ``my_app/static/my_app/myimage.jpg``. -Now, if you use ``./manage.py runserver``, all static files should be served -automatically at the :setting:`STATIC_URL` and be shown correctly. +.. admonition:: Serving the files + + In addition to these configuration steps, you'll also need to actually + serve the static files. + + During development, this will be done automatically if you use + :djadmin:`runserver` and :setting:`DEBUG` is set to ``True`` (see + :func:`django.contrib.staticfiles.views.serve`). + + This method is **grossly inefficient** and probably **insecure**, + so it is **unsuitable for production**. + + See :doc:`/howto/static-files/deployment` for proper strategies to serve + static files in production environments. Your project will probably also have static assets that aren't tied to a particular app. In addition to using a ``static/`` directory inside your apps, diff --git a/docs/howto/upgrade-version.txt b/docs/howto/upgrade-version.txt new file mode 100644 index 0000000000..8777f433f9 --- /dev/null +++ b/docs/howto/upgrade-version.txt @@ -0,0 +1,91 @@ +=================================== +Upgrading Django to a newer version +=================================== + +While it can be a complex process at times, upgrading to the latest Django +version has several benefits: + +* New features and improvements are added. +* Bugs are fixed. +* Older version of Django will eventually no longer receive security updates. + (see :ref:`backwards-compatibility-policy`). +* Upgrading as each new Django release is available makes future upgrades less + painful by keeping your code base up to date. + +Here are some things to consider to help make your upgrade process as smooth as +possible. + +Required Reading +================ + +If it's your first time doing an upgrade, it is useful to read the :doc:`guide +on the different release processes </internals/release-process>`. + +Afterwards, you should familiarize yourself with the changes that were made in +the new Django version(s): + +* Read the :doc:`release notes </releases/index>` for each 'final' release from + the one after your current Django version, up to and including the version to + which you plan to upgrade. +* Look at the :doc:`deprecation timeline</internals/deprecation>` for the + relevant versions. + +Pay particular attention to backwards incompatible changes to get a clear idea +of what will be needed for a successful upgrade. + +Dependencies +============ + +In most cases it will be necessary to upgrade to the latest version of your +Django-related dependencies as well. If the Django version was recently +released or if some of your dependencies are not well-maintained, some of your +dependencies may not yet support the new Django version. In these cases you may +have to wait until new versions of your dependencies are released. + +Installation +============ + +Once you're ready, it is time to :doc:`install the new Django version +</topics/install>`. If you are using virtualenv_ and it is a major upgrade, you +might want to set up a new environment will all the dependencies first. + +Exactly which steps you will need to take depends on your installation process. +The most convenient way is to use pip_ with the ``--upgrade`` or ``-U`` flag: + +.. code-block:: bash + + pip install -U Django + +pip_ also automatically uninstalls the previous version of Django. + +If you use some other installation process, you might have to manually +:ref:`uninstall the old Django version <removing-old-versions-of-django>` and +should look at the complete installation instructions. + +.. _pip: http://www.pip-installer.org/ +.. _virtualenv: http://www.virtualenv.org/ + +Testing +======= + +When the new environment is set up, :doc:`run the full test suite +</topics/testing/overview>` for your application. In Python 2.7+, deprecation +warnings are silenced by default. It is useful to turn the warnings on so they +are shown in the test output (you can also use the flag if you test your app +manually using ``manage.py runserver``): + +.. code-block:: bash + + python -Wall manage.py test + +After you have run the tests, fix any failures. While you have the release +notes fresh in your mind, it may also be a good time to take advantage of new +features in Django by refactoring your code to eliminate any deprecation +warnings. + +Deployment +========== + +When you are sufficiently confident your app works with the new version of +Django, you're ready to go ahead and :doc:`deploy </howto/deployment/index>` +your upgraded Django project. diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt index 6b9c7df14a..b56c8e469b 100644 --- a/docs/internals/committers.txt +++ b/docs/internals/committers.txt @@ -53,6 +53,7 @@ Journal-World`_ of Lawrence, Kansas, USA. .. _revolution systems: http://revsys.com/ .. _wilson miner: http://wilsonminer.com/ .. _heroku: http://heroku.com/ +.. _Rdio: http://rdio.com Current developers ================== @@ -88,6 +89,23 @@ Malcolm Tredinnick *Malcolm passed away on March 17, 2013.* +`Luke Plant`_ + At University Luke studied physics and Materials Science and also + met `Michael Meeks`_ who introduced him to Linux and Open Source, + re-igniting an interest in programming. Since then he has + contributed to a number of Open Source projects and worked + professionally as a developer. + + Luke has contributed many excellent improvements to Django, + including database-level improvements, the CSRF middleware and + many unit tests. + + Luke currently works for a church in Bradford, UK, and part-time + as a freelance developer. + +.. _luke plant: http://lukeplant.me.uk/ +.. _michael meeks: http://en.wikipedia.org/wiki/Michael_Meeks_(software) + `Russell Keith-Magee`_ Russell studied physics as an undergraduate, and studied neural networks for his PhD. His first job was with a startup in the defense industry developing @@ -102,6 +120,42 @@ Malcolm Tredinnick .. _russell keith-magee: http://cecinestpasun.com/ +`James Bennett`_ + James is Django's release manager, and also contributes to the + documentation and provide the occasional bugfix. + + James came to Web development from philosophy when he discovered + that programmers get to argue just as much while collecting much + better pay. He lives in Lawrence, Kansas and previously worked at + World Online; currently, he's part of the Web development team at + Mozilla. + + He `keeps a blog`_, and enjoys fine port and talking to his car. + +.. _james bennett: http://b-list.org/ +.. _keeps a blog: `james bennett`_ + +`Gary Wilson`_ + Gary starting contributing patches to Django in 2006 while developing Web + applications for `The University of Texas`_ (UT). Since, he has made + contributions to the email and forms systems, as well as many other + improvements and code cleanups throughout the code base. + + Gary is currently a developer and software engineering graduate student at + UT, where his dedication to spreading the ways of Python and Django never + ceases. + + Gary lives in Austin, Texas, USA. + +.. _Gary Wilson: http://thegarywilson.com/ +.. _The University of Texas: http://www.utexas.edu/ + +Matt Boersma + Matt is responsible for Django's Oracle support. + +Ian Kelly + Ian is also responsible for Django's support for Oracle. + Joseph Kocherhans Joseph was the director of lead development at EveryBlock and previously developed at the Lawrence Journal-World. He is treasurer of the `Django @@ -119,28 +173,11 @@ Joseph Kocherhans .. _django software foundation: https://www.djangoproject.com/foundation/ .. _charango: http://en.wikipedia.org/wiki/Charango -`Luke Plant`_ - At University Luke studied physics and Materials Science and also - met `Michael Meeks`_ who introduced him to Linux and Open Source, - re-igniting an interest in programming. Since then he has - contributed to a number of Open Source projects and worked - professionally as a developer. - - Luke has contributed many excellent improvements to Django, - including database-level improvements, the CSRF middleware and - many unit tests. - - Luke currently works for a church in Bradford, UK, and part-time - as a freelance developer. - -.. _luke plant: http://lukeplant.me.uk/ -.. _michael meeks: http://en.wikipedia.org/wiki/Michael_Meeks_(software) - `Brian Rosner`_ - Brian is currently the tech lead at Eldarion_ managing and developing + Brian is the Chief Architect at Eldarion_ managing and developing Django / Pinax_ based Web sites. He enjoys learning more about programming languages and system architectures and contributing to open source - projects. Brian is the host of the `Django Dose`_ podcasts. + projects. Brian helped immensely in getting Django's "newforms-admin" branch finished in time for Django 1.0; he's now a full committer, continuing to improve on @@ -150,24 +187,8 @@ Joseph Kocherhans .. _brian rosner: http://brosner.com/ .. _eldarion: http://eldarion.com/ -.. _django dose: http://djangodose.com/ .. _pinax: http://pinaxproject.com/ -`Gary Wilson`_ - Gary starting contributing patches to Django in 2006 while developing Web - applications for `The University of Texas`_ (UT). Since, he has made - contributions to the email and forms systems, as well as many other - improvements and code cleanups throughout the code base. - - Gary is currently a developer and software engineering graduate student at - UT, where his dedication to spreading the ways of Python and Django never - ceases. - - Gary lives in Austin, Texas, USA. - -.. _Gary Wilson: http://thegarywilson.com/ -.. _The University of Texas: http://www.utexas.edu/ - Justin Bronn Justin Bronn is a computer scientist and attorney specializing in legal topics related to intellectual property and spatial law. @@ -222,7 +243,7 @@ Karen Tracey .. _James Tauber: http://jtauber.com/ `Alex Gaynor`_ - Alex is a software engineer working at Rdio_. He found Django in 2007 and + Alex is a software engineer working at Rackspace_. He found Django in 2007 and has been addicted ever since he found out you don't need to write out your forms by hand. He has a small obsession with compilers. He's contributed to the ORM, forms, admin, and other components of Django. @@ -230,7 +251,16 @@ Karen Tracey Alex lives in San Francisco, CA, USA. .. _Alex Gaynor: http://alexgaynor.net -.. _Rdio: http://rdio.com +.. _Rackspace: http://www.rackspace.com + +`Simon Meers`_ + Simon discovered Django 0.96 during his Computer Science PhD research and + has been developing with it full-time ever since. His core code + contributions are mostly in Django's admin application. + + Simon works as a freelance developer based in Wollongong, Australia. + +.. _Simon Meers: http://simonmeers.com/ `Andrew Godwin`_ Andrew is a freelance Python developer and tinkerer, and has been @@ -265,6 +295,18 @@ Ramiro Morales Ramiro lives in Córdoba, Argentina. +`Gabriel Hurley`_ + Gabriel has been working with Django since 2008, shortly after the 1.0 + release. Convinced by his business partner that Python and Django were the + right direction for the company, he couldn't have been more happy with the + decision. His contributions range across many areas in Django, but years of + copy-editing and an eye for detail lead him to be particularly at home + while working on Django's documentation. + + Gabriel works as a web developer in Berkeley, CA, USA. + +.. _gabriel hurley: http://strikeawe.com/ + `Chris Beaven`_ Chris has been submitting patches and suggesting crazy ideas for Django since early 2006. An advocate for community involvement and a long-term @@ -290,6 +332,13 @@ Honza Král .. _Whiskey Media: http://www.whiskeymedia.com/ +Tim Graham + When exploring Web frameworks for an independent study project in the fall + of 2008, Tim discovered Django and was lured to it by the documentation. + He enjoys contributing to the docs because they're awesome. + + Tim works as a software engineer and lives in Philadelphia, PA, USA. + `Idan Gazit`_ As a self-professed design geek, Idan was initially attracted to Django sometime between magic-removal and queryset-refactor. Formally trained @@ -439,6 +488,18 @@ Jeremy Dunck .. _Ultimate Frisbee: http://www.montrealultimate.ca .. _Reptiletech: http://www.reptiletech.com +Donald Stufft + Donald found Python and Django in 2007 while trying to find a language, + and web framework that he really enjoyed using after many years of PHP. He + fell in love with the beauty of Python and the way Django made tasks simple + and easy. His contributions to Django focus primarily on ensuring that it + is and remains a secure web framework. + + Donald currently works at `Nebula Inc`_ as a Software Engineer for their + security team and lives in the Greater Philadelphia Area. + +.. _Nebula Inc: https://www.nebula.com/ + `Daniel Lindsley`_ Pythonista since 2003, Djangonaut since 2006. Daniel started with Django just after the v0.90 release (back when ``Manipulators`` looked good) & fell @@ -453,56 +514,6 @@ Jeremy Dunck .. _`Daniel Lindsley`: http://toastdriven.com/ .. _`Amazon Web Services`: https://aws.amazon.com/ -`James Bennett`_ - James is Django's release manager, and also contributes to the - documentation and provide the occasional bugfix. - - James came to Web development from philosophy when he discovered - that programmers get to argue just as much while collecting much - better pay. He lives in Lawrence, Kansas and previously worked at - World Online; currently, he's part of the Web development team at - Mozilla. - - He `keeps a blog`_, and enjoys fine port and talking to his car. - -.. _james bennett: http://b-list.org/ -.. _keeps a blog: `james bennett`_ - -Ian Kelly - Ian is responsible for Django's support for Oracle. - -Matt Boersma - Matt is also responsible for Django's Oracle support. - -`Simon Meers`_ - Simon discovered Django 0.96 during his Computer Science PhD research and - has been developing with it full-time ever since. His core code - contributions are mostly in Django's admin application. He is also helping - to improve Django's documentation. - - Simon works as a freelance developer based in Wollongong, Australia. - -.. _simon meers: http://simonmeers.com/ - -`Gabriel Hurley`_ - Gabriel has been working with Django since 2008, shortly after the 1.0 - release. Convinced by his business partner that Python and Django were the - right direction for the company, he couldn't have been more happy with the - decision. His contributions range across many areas in Django, but years of - copy-editing and an eye for detail lead him to be particularly at home - while working on Django's documentation. - - Gabriel works as a web developer in Berkeley, CA, USA. - -.. _gabriel hurley: http://strikeawe.com/ - -Tim Graham - When exploring Web frameworks for an independent study project in the fall - of 2008, Tim discovered Django and was lured to it by the documentation. - He enjoys contributing to the docs because they're awesome. - - Tim works as a software engineer and lives in Philadelphia, PA, USA. - Marc Tamlyn Marc started life on the web using Django 1.2 back in 2010, and has never looked back. He was involved with rewriting the class based view @@ -515,18 +526,6 @@ Marc Tamlyn .. _CCBV: http://ccbv.co.uk/ .. _Incuna Ltd: http://incuna.com/ -Donald Stufft - Donald found Python and Django in 2007 while trying to find a language, - and web framework that he really enjoyed using after many years of PHP. He - fell in love with the beauty of Python and the way Django made tasks simple - and easy. His contributions to Django focus primarily on ensuring that it - is and remains a secure web framework. - - Donald currently works at `Nebula Inc`_ as a Software Engineer for their - security team and lives in the Greater Philadelphia Area. - -.. _Nebula Inc: https://www.nebula.com/ - Developers Emeritus =================== diff --git a/docs/internals/contributing/triaging-tickets.txt b/docs/internals/contributing/triaging-tickets.txt index bc6148ca46..43b799ed51 100644 --- a/docs/internals/contributing/triaging-tickets.txt +++ b/docs/internals/contributing/triaging-tickets.txt @@ -349,8 +349,9 @@ Then, you can help out by: * Closing "Unreviewed" tickets as "invalid", "worksforme" or "duplicate." -* Closing "Unreviewed" tickets as "needsinfo" when they're feature requests - requiring a discussion on `django-developers`_. +* Closing "Unreviewed" tickets as "needsinfo" when the description is too + sparse to be actionnable, or when they're feature requests requiring a + discussion on `django-developers`_. * Correcting the "Needs tests", "Needs documentation", or "Has patch" flags for tickets where they are incorrectly set. diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index f56bf1cdeb..0737b84888 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -27,15 +27,13 @@ Quickstart Running the tests requires a Django settings module that defines the databases to use. To make it easy to get started, Django provides a sample settings module that uses the SQLite database. To run the tests -with this sample ``settings`` module, ``cd`` into the Django -``tests/`` directory and run: +with this sample ``settings`` module: .. code-block:: bash - ./runtests.py --settings=test_sqlite - -If you get an ``ImportError: No module named django.contrib`` error, -you need to add your install of Django to your ``PYTHONPATH``. + git clone git@github.com:django/django.git django-repo + cd django-repo/tests + PYTHONPATH=..:$PYTHONPATH python ./runtests.py --settings=test_sqlite .. _running-unit-tests-settings: @@ -47,14 +45,10 @@ SQLite. If you want to test behavior using a different database (and if you're proposing patches for Django, it's a good idea to test across databases), you may need to define your own settings file. -To run the tests with different settings, ``cd`` to the ``tests/`` directory -and type: - -.. code-block:: bash - - ./runtests.py --settings=path.to.django.settings +To run the tests with different settings, ensure that the module is on your +``PYTHONPATH`` and pass the module with ``--settings``. -The :setting:`DATABASES` setting in this test settings module needs to define +The :setting:`DATABASES` setting in any test settings module needs to define two databases: * A ``default`` database. This database should use the backend that diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 774de2a2fd..45f82b49e6 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -373,6 +373,7 @@ these changes. * The following private APIs will be removed: + - ``django.db.backend`` - ``django.db.close_connection()`` - ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()`` - ``django.db.transaction.is_managed()`` @@ -385,10 +386,15 @@ these changes. ``django.test.simple.DjangoTestSuiteRunner`` will be removed. Instead use ``django.test.runner.DiscoverRunner``. -* The module ``django.test._doctest`` and the classes - ``django.test.testcases.DocTestRunner`` and - ``django.test.testcases.OutputChecker`` will be removed. Instead use the - doctest module from the Python standard library. +* The module ``django.test._doctest`` will be removed. Instead use the doctest + module from the Python standard library. + +* The ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting will be removed. + +* Usage of the hard-coded *Hold down "Control", or "Command" on a Mac, to select + more than one.* string to override or append to user-provided ``help_text`` in + forms for ManyToMany model fields will not be performed by Django anymore + either at the model or forms layer. 2.0 --- diff --git a/docs/internals/git.txt b/docs/internals/git.txt index 2b1a279d89..3904ff83d4 100644 --- a/docs/internals/git.txt +++ b/docs/internals/git.txt @@ -35,8 +35,9 @@ The Git repository includes several `branches`_: the next packaged release of Django. This is where most development activity is focused. -* ``stable/A.B.x`` are the maintenance branches. They are used to support - older versions of Django. +* ``stable/A.B.x`` are the branches where release preparation work happens. + They are also used for support and bugfix releases which occur as necessary + after the initial release of a major or minor version. * ``soc20XX/<project>`` branches were used by students who worked on Django during the 2009 and 2010 Google Summer of Code programs. @@ -83,13 +84,50 @@ coding style and how to generate and submit a patch. Other branches ============== -Django uses branches for two main purposes: +Django uses branches to prepare for releases of Django (whether they be +:term:`major <Major release>`, :term:`minor <Minor release>`, or +:term:`micro <Micro release>`). -1. Development of major or experimental features, to keep them from - affecting progress on other work in master. +In the past when Django was hosted on Subversion, branches were also used for +feature development. Now Django is hosted on Git and feature development is +done on contributor's forks, but the Subversion feature branches remain in Git +for historical reference. -2. Security and bugfix support for older releases of Django, during - their support lifetimes. +Stable branches +--------------- + +These branches can be found in the repository as ``stable/A.B.x`` +branches and will be created right after the first alpha is tagged. + +For example, immediately after *Django 1.5 alpha 1* was tagged, the branch +``stable/1.5.x`` was created and all further work on preparing the code for the +final 1.5 release was done there. + +These branches also provide limited bugfix support for the most recent released +version of Django and security support for the two most recently-released +versions of Django. + +For example, after the release of Django 1.5, the branch ``stable/1.5.x`` +receives only fixes for security and critical stability bugs, which are +eventually released as Django 1.5.1 and so on, ``stable/1.4.x`` receives only +security fixes, and ``stable/1.3.x`` no longer receives any updates. + +.. admonition:: Historical information + + This policy for handling ``stable/A.B.x`` branches was adopted starting + with the Django 1.5 release cycle. + + Previously, these branches weren't created until right after the releases + and the stabilization work occurred on the main repository branch. Thus, + no new features development work for the next release of Django could be + committed until the final release happened. + + For example, shortly after the release of Django 1.3 the branch + ``stable/1.3.x`` was created. Official support for that release has expired, + and so it no longer receives direct maintenance from the Django project. + However, that and all other similarly named branches continue to exist and + interested community members have occasionally used them to provide + unofficial support for old Django releases. Feature-development branches ---------------------------- @@ -203,30 +241,6 @@ All of the above-mentioned branches now reside in ``attic``. Finally, the repository contains ``soc2009/xxx`` and ``soc2010/xxx`` feature branches, used for Google Summer of Code projects. -Support and bugfix branches ---------------------------- - -In addition to fixing bugs in current master, the Django project provides -official bugfix support for the most recent released version of Django, and -security support for the two most recently-released versions of Django. - -This support is provided via branches in which the necessary bug or security -fixes are applied; the branches are then used as the basis for issuing bugfix -or security releases. - -These branches can be found in the repository as ``stable/A.B.x`` -branches, and new branches will be created there after each new Django -release. - -For example, shortly after the release of Django 1.0, the branch -``stable/1.0.x`` was created to receive bug fixes, and shortly after the -release of Django 1.1 the branch ``stable/1.1.x`` was created. - -Official support for the above mentioned releases has expired, and so they no -longer receive direct maintenance from the Django project. However, the -branches continue to exist and interested community members have occasionally -used them to provide unofficial support for old Django releases. - Tags ==== diff --git a/docs/internals/howto-release-django.txt b/docs/internals/howto-release-django.txt index fd985ddafc..5bda2e8add 100644 --- a/docs/internals/howto-release-django.txt +++ b/docs/internals/howto-release-django.txt @@ -183,13 +183,46 @@ OK, this is the fun part, where we actually push out a release! $ md5sum dist/Django-* $ sha1sum dist/Django-* - *FIXME: perhaps we should switch to sha256?* - #. Create a "checksums" file containing the hashes and release information. - You can start with `a previous checksums file`__ and replace the - dates, keys, links, and checksums. *FIXME: make a template file.* + Start with this template and insert the correct version, date, release URL + and checksums:: + + This file contains MD5 and SHA1 checksums for the source-code tarball + of Django <<VERSION>>, released <<DATE>>. + + To use this file, you will need a working install of PGP or other + compatible public-key encryption software. You will also need to have + the Django release manager's public key in your keyring; this key has + the ID ``0x3684C0C08C8B2AE1`` and can be imported from the MIT + keyserver. For example, if using the open-source GNU Privacy Guard + implementation of PGP:: + + gpg --keyserver pgp.mit.edu --recv-key 0x3684C0C08C8B2AE1 + + Once the key is imported, verify this file:: + + gpg --verify <<THIS FILENAME>> + + Once you have verified this file, you can use normal MD5 and SHA1 + checksumming applications to generate the checksums of the Django + package and compare them to the checksums listed below. + + + Release package: + ================ + + Django <<VERSION>>: https://www.djangoproject.com/m/releases/<<URL>> + + + MD5 checksum: + ============= + + MD5(<<RELEASE TAR.GZ FILENAME>>)= <<MD5SUM>> + + SHA1 checksum: + ============== - __ https://www.djangoproject.com/m/pgp/Django-1.5b1.checksum.txt + SHA1(<<RELEASE TAR.GZ FILENAME>>)= <<SHA1SUM>> #. Sign the checksum file (``gpg --clearsign Django-<version>.checksum.txt``). This generates a signed document, @@ -268,8 +301,7 @@ Now you're ready to actually put the release out there. To do this: of the docs by flipping the ``is_default`` flag to ``True`` on the appropriate ``DocumentRelease`` object in the ``docs.djangoproject.com`` database (this will automatically flip it to ``False`` for all - others). *FIXME: I had to do this via fab managepy:shell,docs but we should - probably make it possible to do via the admin.* + others); you can do this using the site's admin. #. Post the release announcement to the django-announce, django-developers and django-users mailing lists. This should @@ -289,7 +321,8 @@ You're almost done! All that's left to do now is: ``stable/1.?.x`` git branch), you'll want to create a new ``DocumentRelease`` object in the ``docs.djangoproject.com`` database for the new version's docs, and update the ``docs/fixtures/doc_releases.json`` - JSON fixture. *FIXME: what is the purpose of maintaining this fixture?* + JSON fixture, so people without access to the production DB can still + run an up-to-date copy of the docs site. #. Add the release in `Trac's versions list`_ if necessary. Not all versions are declared; take example on previous releases. diff --git a/docs/internals/release-process.txt b/docs/internals/release-process.txt index 29ce3914b4..2003e79079 100644 --- a/docs/internals/release-process.txt +++ b/docs/internals/release-process.txt @@ -39,49 +39,45 @@ issued from those branches. For more information about how the Django project issues new releases for security purposes, please see :doc:`our security policies <security>`. -Major releases --------------- +.. glossary:: -Major releases (1.0, 2.0, etc.) will happen very infrequently (think "years", -not "months"), and may represent major, sweeping changes to Django. + Major release + Major releases (1.0, 2.0, etc.) will happen very infrequently (think "years", + not "months"), and may represent major, sweeping changes to Django. -Minor releases --------------- + Minor release + Minor release (1.5, 1.6, etc.) will happen roughly every nine months -- see + `release process`_, below for details. These releases will contain new + features, improvements to existing features, and such. -Minor release (1.5, 1.6, etc.) will happen roughly every nine months -- see -`release process`_, below for details. These releases will contain new -features, improvements to existing features, and such. + .. _internal-release-deprecation-policy: -.. _internal-release-deprecation-policy: + A minor release may deprecate certain features from previous releases. If a + feature is deprecated in version ``A.B``, it will continue to work in versions + ``A.B`` and ``A.B+1`` but raise warnings. It will be removed in version + ``A.B+2``. -A minor release may deprecate certain features from previous releases. If a -feature is deprecated in version ``A.B``, it will continue to work in versions -``A.B`` and ``A.B+1`` but raise warnings. It will be removed in version -``A.B+2``. + So, for example, if we decided to start the deprecation of a function in + Django 1.5: -So, for example, if we decided to start the deprecation of a function in -Django 1.5: + * Django 1.5 will contain a backwards-compatible replica of the function which + will raise a ``PendingDeprecationWarning``. This warning is silent by + default; you can turn on display of these warnings with the ``-Wd`` option + of Python. -* Django 1.5 will contain a backwards-compatible replica of the function which - will raise a ``PendingDeprecationWarning``. This warning is silent by - default; you can turn on display of these warnings with the ``-Wd`` option - of Python. + * Django 1.6 will contain the backwards-compatible replica, but the warning + will be promoted to a full-fledged ``DeprecationWarning``. This warning is + *loud* by default, and will likely be quite annoying. -* Django 1.6 will contain the backwards-compatible replica, but the warning - will be promoted to a full-fledged ``DeprecationWarning``. This warning is - *loud* by default, and will likely be quite annoying. + * Django 1.7 will remove the feature outright. -* Django 1.7 will remove the feature outright. + Micro release + Micro releases (1.5.1, 1.6.2, 1.6.1, etc.) will be issued as needed, often to + fix security issues. -Micro releases --------------- - -Micro releases (1.5.1, 1.6.2, 1.6.1, etc.) will be issued as needed, often to -fix security issues. - -These releases will be 100% compatible with the associated minor release, unless -this is impossible for security reasons. So the answer to "should I upgrade to -the latest micro release?" will always be "yes." + These releases will be 100% compatible with the associated minor release, unless + this is impossible for security reasons. So the answer to "should I upgrade to + the latest micro release?" will always be "yes." .. _backwards-compatibility-policy: @@ -126,15 +122,15 @@ Django 1.6 and 1.7. At this point in time: * Features will be added to development master, to be released as Django 1.7. -* Critical bug fixes will be applied to the ``stable/1.6.X`` branch, and +* Critical bug fixes will be applied to the ``stable/1.6.x`` branch, and released as 1.6.1, 1.6.2, etc. -* Security fixes will be applied to ``master``, to the ``stable/1.6.X`` - branch, and to the ``stable/1.5.X`` branch. They will trigger the release of +* Security fixes will be applied to ``master``, to the ``stable/1.6.x`` + branch, and to the ``stable/1.5.x`` branch. They will trigger the release of ``1.6.1``, ``1.5.1``, etc. * Documentation fixes will be applied to master, and, if easily backported, to - the ``1.6.X`` branch. Bugfixes may also be backported. + the ``1.6.x`` branch. Bugfixes may also be backported. .. _release-process: @@ -193,9 +189,9 @@ Phase two will culminate with an alpha release. At this point, the Phase three: bugfixes ~~~~~~~~~~~~~~~~~~~~~ -The last third of a release is spent fixing bugs -- no new features will be -accepted during this time. We'll try to release a beta release after one month -and a release candidate after two months. +The last third of a release cycle is spent fixing bugs -- no new features will +be accepted during this time. We'll try to release a beta release after one +month and a release candidate after two months. The release candidate marks the string freeze, and it happens at least two weeks before the final release. After this point, new translatable strings diff --git a/docs/intro/overview.txt b/docs/intro/overview.txt index 8753817256..77838ffcaa 100644 --- a/docs/intro/overview.txt +++ b/docs/intro/overview.txt @@ -16,14 +16,18 @@ Design your model ================= Although you can use Django without a database, it comes with an -object-relational mapper in which you describe your database layout in Python +`object-relational mapper`_ in which you describe your database layout in Python code. +.. _object-relational mapper: http://en.wikipedia.org/wiki/Object-relational_mapping + The :doc:`data-model syntax </topics/db/models>` offers many rich ways of representing your models -- so far, it's been solving two years' worth of database-schema problems. Here's a quick example, which might be saved in the file ``mysite/news/models.py``:: + from django.db import models + class Reporter(models.Model): full_name = models.CharField(max_length=70) @@ -55,8 +59,9 @@ tables in your database for whichever tables don't already exist. Enjoy the free API ================== -With that, you've got a free, and rich, :doc:`Python API </topics/db/queries>` to -access your data. The API is created on the fly, no code generation necessary: +With that, you've got a free, and rich, :doc:`Python API </topics/db/queries>` +to access your data. The API is created on the fly, no code generation +necessary: .. code-block:: python @@ -133,9 +138,9 @@ A dynamic admin interface: it's not just scaffolding -- it's the whole house ============================================================================ Once your models are defined, Django can automatically create a professional, -production ready :doc:`administrative interface </ref/contrib/admin/index>` -- a Web -site that lets authenticated users add, change and delete objects. It's as easy -as registering your model in the admin site:: +production ready :doc:`administrative interface </ref/contrib/admin/index>` -- +a Web site that lets authenticated users add, change and delete objects. It's +as easy as registering your model in the admin site:: # In models.py... @@ -171,9 +176,9 @@ application. Django encourages beautiful URL design and doesn't put any cruft in URLs, like ``.php`` or ``.asp``. To design URLs for an app, you create a Python module called a :doc:`URLconf -</topics/http/urls>`. A table of contents for your app, it contains a simple mapping -between URL patterns and Python callback functions. URLconfs also serve to -decouple URLs from Python code. +</topics/http/urls>`. A table of contents for your app, it contains a simple +mapping between URL patterns and Python callback functions. URLconfs also serve +to decouple URLs from Python code. Here's what a URLconf might look like for the ``Reporter``/``Article`` example above:: @@ -186,7 +191,7 @@ example above:: (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'), ) -The code above maps URLs, as simple regular expressions, to the location of +The code above maps URLs, as simple `regular expressions`_, to the location of Python callback functions ("views"). The regular expressions use parenthesis to "capture" values from the URLs. When a user requests a page, Django runs through each pattern, in order, and stops at the first one that matches the @@ -194,6 +199,8 @@ requested URL. (If none of them matches, Django calls a special-case 404 view.) This is blazingly fast, because the regular expressions are compiled at load time. +.. _regular expressions: http://docs.python.org/2/howto/regex.html + Once one of the regexes matches, Django imports and calls the given view, which is a simple Python function. Each view gets passed a request object -- which contains request metadata -- and the values captured in the regex. @@ -214,6 +221,8 @@ Generally, a view retrieves data according to the parameters, loads a template and renders the template with the retrieved data. Here's an example view for ``year_archive`` from above:: + from django.shortcuts import render_to_response + def year_archive(request, year): a_list = Article.objects.filter(pub_date__year=year) return render_to_response('news/year_archive.html', {'year': year, 'article_list': a_list}) @@ -229,8 +238,8 @@ The code above loads the ``news/year_archive.html`` template. Django has a template search path, which allows you to minimize redundancy among templates. In your Django settings, you specify a list of directories to check -for templates. If a template doesn't exist in the first directory, it checks the -second, and so on. +for templates with :setting:`TEMPLATE_DIRS`. If a template doesn't exist in the +first directory, it checks the second, and so on. Let's say the ``news/year_archive.html`` template was found. Here's what that might look like: @@ -261,9 +270,10 @@ character). This is called a template filter, and it's a way to filter the value of a variable. In this case, the date filter formats a Python datetime object in the given format (as found in PHP's date function). -You can chain together as many filters as you'd like. You can write custom -filters. You can write custom template tags, which run custom Python code behind -the scenes. +You can chain together as many filters as you'd like. You can write :ref:`custom +template filters <howto-writing-custom-template-filters>`. You can write +:doc:`custom template tags </howto/custom-template-tags>`, which run custom +Python code behind the scenes. Finally, Django uses the concept of "template inheritance": That's what the ``{% extends "base.html" %}`` does. It means "First load the template called diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt index d623bd8451..6e5988b15a 100644 --- a/docs/intro/tutorial01.txt +++ b/docs/intro/tutorial01.txt @@ -582,6 +582,8 @@ of this object. Let's fix that by editing the polls model (in the ``Choice``. On Python 3, simply replace ``__unicode__`` by ``__str__`` in the following example:: + from django.db import models + class Poll(models.Model): # ... def __unicode__(self): # Python 3: def __str__(self): diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt index 1987c51a67..dd3e86d8ae 100644 --- a/docs/intro/tutorial02.txt +++ b/docs/intro/tutorial02.txt @@ -158,6 +158,9 @@ you want when you register the object. Let's see how this works by re-ordering the fields on the edit form. Replace the ``admin.site.register(Poll)`` line with:: + from django.contrib import admin + from polls.models import Poll + class PollAdmin(admin.ModelAdmin): fields = ['pub_date', 'question'] @@ -179,6 +182,9 @@ of fields, choosing an intuitive order is an important usability detail. And speaking of forms with dozens of fields, you might want to split the form up into fieldsets:: + from django.contrib import admin + from polls.models import Poll + class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question']}), @@ -198,6 +204,9 @@ You can assign arbitrary HTML classes to each fieldset. Django provides a This is useful when you have a long form that contains a number of fields that aren't commonly used:: + from django.contrib import admin + from polls.models import Poll + class PollAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['question']}), @@ -218,6 +227,7 @@ Yet. There are two ways to solve this problem. The first is to register ``Choice`` with the admin just as we did with ``Poll``. That's easy:: + from django.contrib import admin from polls.models import Choice admin.site.register(Choice) @@ -342,6 +352,12 @@ representation of the output. You can improve that by giving that method (in :file:`polls/models.py`) a few attributes, as follows:: + import datetime + from django.utils import timezone + from django.db import models + + from polls.models import Poll + class Poll(models.Model): # ... def was_published_recently(self): diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index 86cc5f97e6..120369172e 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -336,7 +336,7 @@ Put the following code in that template: <p>No polls are available.</p> {% endif %} -Now let's use that html template in our index view:: +Now let's update our ``index`` view in ``polls/views.py`` to use the template:: from django.http import HttpResponse from django.template import Context, loader @@ -393,6 +393,9 @@ Now, let's tackle the poll detail view -- the page that displays the question for a given poll. Here's the view:: from django.http import Http404 + from django.shortcuts import render + + from polls.models import Poll # ... def detail(request, poll_id): try: @@ -420,6 +423,8 @@ and raise :exc:`~django.http.Http404` if the object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view, rewritten:: from django.shortcuts import render, get_object_or_404 + + from polls.models import Poll # ... def detail(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt index 9f54243a3e..f81a7d6758 100644 --- a/docs/intro/tutorial04.txt +++ b/docs/intro/tutorial04.txt @@ -136,6 +136,8 @@ object. For more on :class:`~django.http.HttpRequest` objects, see the After somebody votes in a poll, the ``vote()`` view redirects to the results page for the poll. Let's write that view:: + from django.shortcuts import get_object_or_404, render + def results(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) return render(request, 'polls/results.html', {'poll': poll}) diff --git a/docs/intro/tutorial05.txt b/docs/intro/tutorial05.txt index a276763d67..39c3785f7c 100644 --- a/docs/intro/tutorial05.txt +++ b/docs/intro/tutorial05.txt @@ -503,8 +503,8 @@ of the process of creating polls. message: "No polls are available." and verifies the ``latest_poll_list`` is empty. Note that the :class:`django.test.TestCase` class provides some additional assertion methods. In these examples, we use -:meth:`~django.test.TestCase.assertContains()` and -:meth:`~django.test.TestCase.assertQuerysetEqual()`. +:meth:`~django.test.SimpleTestCase.assertContains()` and +:meth:`~django.test.TransactionTestCase.assertQuerysetEqual()`. In ``test_index_view_with_a_past_poll``, we create a poll and verify that it appears in the list. diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt index ee0bf0f225..319bd4ebfe 100644 --- a/docs/ref/class-based-views/base.txt +++ b/docs/ref/class-based-views/base.txt @@ -55,7 +55,7 @@ View Default:: - ['get', 'post', 'put', 'delete', 'head', 'options', 'trace'] + ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] **Methods** @@ -114,7 +114,6 @@ TemplateView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.base.TemplateView` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.base.View` @@ -208,7 +207,7 @@ RedirectView urlpatterns = patterns('', - url(r'r^(?P<pk>\d+)/$', ArticleCounterRedirectView.as_view(), name='article-counter'), + url(r'^(?P<pk>\d+)/$', ArticleCounterRedirectView.as_view(), name='article-counter'), url(r'^go-to-django/$', RedirectView.as_view(url='http://djangoproject.com'), name='go-to-django'), ) diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt index 4dcb788779..1ebee254b1 100644 --- a/docs/ref/class-based-views/generic-date-based.txt +++ b/docs/ref/class-based-views/generic-date-based.txt @@ -33,7 +33,6 @@ ArchiveIndexView **Ancestors (MRO)** - * :class:`django.views.generic.dates.ArchiveIndexView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseArchiveIndexView` @@ -100,7 +99,6 @@ YearArchiveView **Ancestors (MRO)** - * :class:`django.views.generic.dates.YearArchiveView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseYearArchiveView` @@ -216,7 +214,6 @@ MonthArchiveView **Ancestors (MRO)** - * :class:`django.views.generic.dates.MonthArchiveView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseMonthArchiveView` @@ -317,7 +314,6 @@ WeekArchiveView **Ancestors (MRO)** - * :class:`django.views.generic.dates.WeekArchiveView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseWeekArchiveView` @@ -422,7 +418,6 @@ DayArchiveView **Ancestors (MRO)** - * :class:`django.views.generic.dates.DayArchiveView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseDayArchiveView` @@ -526,7 +521,6 @@ TodayArchiveView **Ancestors (MRO)** - * :class:`django.views.generic.dates.TodayArchiveView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseTodayArchiveView` @@ -585,7 +579,6 @@ DateDetailView **Ancestors (MRO)** - * :class:`django.views.generic.dates.DateDetailView` * :class:`django.views.generic.detail.SingleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.dates.BaseDateDetailView` diff --git a/docs/ref/class-based-views/generic-display.txt b/docs/ref/class-based-views/generic-display.txt index b827c0005c..c133134d65 100644 --- a/docs/ref/class-based-views/generic-display.txt +++ b/docs/ref/class-based-views/generic-display.txt @@ -77,7 +77,6 @@ ListView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.list.ListView` * :class:`django.views.generic.list.MultipleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * :class:`django.views.generic.list.BaseListView` diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt index 555ba40cfb..c1fb2dcca9 100644 --- a/docs/ref/class-based-views/generic-editing.txt +++ b/docs/ref/class-based-views/generic-editing.txt @@ -36,7 +36,6 @@ FormView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.edit.FormView` * :class:`django.views.generic.base.TemplateResponseMixin` * ``django.views.generic.edit.BaseFormView`` * :class:`django.views.generic.edit.FormMixin` @@ -83,7 +82,6 @@ CreateView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.edit.CreateView` * :class:`django.views.generic.detail.SingleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * ``django.views.generic.edit.BaseCreateView`` @@ -126,7 +124,6 @@ UpdateView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.edit.UpdateView` * :class:`django.views.generic.detail.SingleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * ``django.views.generic.edit.BaseUpdateView`` @@ -169,7 +166,6 @@ DeleteView This view inherits methods and attributes from the following views: - * :class:`django.views.generic.edit.DeleteView` * :class:`django.views.generic.detail.SingleObjectTemplateResponseMixin` * :class:`django.views.generic.base.TemplateResponseMixin` * ``django.views.generic.edit.BaseDeleteView`` diff --git a/docs/ref/class-based-views/index.txt b/docs/ref/class-based-views/index.txt index a027953416..821edc0874 100644 --- a/docs/ref/class-based-views/index.txt +++ b/docs/ref/class-based-views/index.txt @@ -32,7 +32,7 @@ A class-based view is deployed into a URL pattern using the .. admonition:: Thread safety with view arguments Arguments passed to a view are shared between every instance of a view. - This means that you shoudn't use a list, dictionary, or any other + This means that you shouldn't use a list, dictionary, or any other mutable object as an argument to a view. If you do and the shared object is modified, the actions of one user visiting your view could have an effect on subsequent users visiting the same view. diff --git a/docs/ref/class-based-views/mixins-editing.txt b/docs/ref/class-based-views/mixins-editing.txt index 51d8628818..48d363b3b2 100644 --- a/docs/ref/class-based-views/mixins-editing.txt +++ b/docs/ref/class-based-views/mixins-editing.txt @@ -125,7 +125,7 @@ ModelFormMixin This is a required attribute if you are generating the form class automatically (e.g. using ``model``). Omitting this attribute will - result in all fields being used, but this behaviour is deprecated + result in all fields being used, but this behavior is deprecated and will be removed in Django 1.8. .. attribute:: success_url diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt index 6796675529..377c85cc3b 100644 --- a/docs/ref/class-based-views/mixins-simple.txt +++ b/docs/ref/class-based-views/mixins-simple.txt @@ -60,6 +60,17 @@ TemplateResponseMixin altered later (e.g. in :ref:`template response middleware <template-response-middleware>`). + .. admonition:: Context processors + + ``TemplateResponse`` uses :class:`~django.template.RequestContext` + which means that callables defined in + :setting:`TEMPLATE_CONTEXT_PROCESSORS` may overwrite template + variables defined in your views. For example, if you subclass + :class:`DetailView <django.views.generic.detail.DetailView>` and + set ``context_object_name`` to ``user``, the + ``django.contrib.auth.context_processors.auth`` context processor + will happily overwrite your variable with current user. + If you need custom template loading or custom context object instantiation, create a ``TemplateResponse`` subclass and assign it to ``response_class``. diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt index 394d078e5b..6deb7bdbf8 100644 --- a/docs/ref/contrib/admin/admindocs.txt +++ b/docs/ref/contrib/admin/admindocs.txt @@ -30,8 +30,8 @@ the following: * Install the docutils Python module (http://docutils.sf.net/). * **Optional:** Linking to templates requires the :setting:`ADMIN_FOR` setting to be configured. -* **Optional:** Using the admindocs bookmarklets requires the - :mod:`XViewMiddleware<django.middleware.doc>` to be installed. +* **Optional:** Using the admindocs bookmarklets requires + ``django.contrib.admindocs.middleware.XViewMiddleware`` to be installed. Once those steps are complete, you can start browsing the documentation by going to your admin interface and clicking the "Documentation" link in the @@ -156,7 +156,6 @@ Edit this object Using these bookmarklets requires that you are either logged into the :mod:`Django admin <django.contrib.admin>` as a :class:`~django.contrib.auth.models.User` with -:attr:`~django.contrib.auth.models.User.is_staff` set to `True`, or -that the :mod:`django.middleware.doc` middleware and -:mod:`XViewMiddleware <django.middleware.doc>` are installed and you -are accessing the site from an IP address listed in :setting:`INTERNAL_IPS`. +:attr:`~django.contrib.auth.models.User.is_staff` set to `True`, or that the +``XViewMiddleware`` is installed and you are accessing the site from an IP +address listed in :setting:`INTERNAL_IPS`. diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 67e498ee91..7377f11a63 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -108,6 +108,8 @@ The ``ModelAdmin`` is very flexible. It has several options for dealing with customizing the interface. All options are defined on the ``ModelAdmin`` subclass:: + from django.contrib import admin + class AuthorAdmin(admin.ModelAdmin): date_hierarchy = 'pub_date' @@ -157,6 +159,8 @@ subclass:: For example, let's consider the following model:: + from django.db import models + class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3) @@ -166,6 +170,8 @@ subclass:: and ``title`` fields, you would specify ``fields`` or ``exclude`` like this:: + from django.contrib import admin + class AuthorAdmin(admin.ModelAdmin): fields = ('name', 'title') @@ -234,6 +240,8 @@ subclass:: A full example, taken from the :class:`django.contrib.flatpages.models.FlatPage` model:: + from django.contrib import admin + class FlatPageAdmin(admin.ModelAdmin): fieldsets = ( (None, { @@ -356,6 +364,10 @@ subclass:: If your ``ModelForm`` and ``ModelAdmin`` both define an ``exclude`` option then ``ModelAdmin`` takes precedence:: + from django import forms + from django.contrib import admin + from myapp.models import Person + class PersonForm(forms.ModelForm): class Meta: @@ -452,13 +464,16 @@ subclass:: list_display = ('upper_case_name',) def upper_case_name(self, obj): - return ("%s %s" % (obj.first_name, obj.last_name)).upper() + return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = 'Name' * A string representing an attribute on the model. This behaves almost the same as the callable, but ``self`` in this context is the model instance. Here's a full model example:: + from django.db import models + from django.contrib import admin + class Person(models.Model): name = models.CharField(max_length=50) birthday = models.DateField() @@ -494,6 +509,8 @@ subclass:: Here's a full example model:: + from django.db import models + from django.contrib import admin from django.utils.html import format_html class Person(models.Model): @@ -519,6 +536,9 @@ subclass:: Here's a full example model:: + from django.db import models + from django.contrib import admin + class Person(models.Model): first_name = models.CharField(max_length=50) birthday = models.DateField() @@ -547,6 +567,8 @@ subclass:: For example:: + from django.db import models + from django.contrib import admin from django.utils.html import format_html class Person(models.Model): @@ -567,6 +589,27 @@ subclass:: The above will tell Django to order by the ``first_name`` field when trying to sort by ``colored_first_name`` in the admin. + * Elements of ``list_display`` can also be properties. Please note however, + that due to the way properties work in Python, setting + ``short_description`` on a property is only possible when using the + ``property()`` function and **not** with the ``@property`` decorator. + + For example:: + + class Person(object): + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + + def my_property(self): + return self.first_name + ' ' + self.last_name + my_property.short_description = "Full name of the person" + + full_name = property(my_property) + + class PersonAdmin(admin.ModelAdmin): + list_display = ('full_name',) + + * .. versionadded:: 1.6 The field names in ``list_display`` will also appear as CSS classes in @@ -634,13 +677,13 @@ subclass:: ``BooleanField``, ``CharField``, ``DateField``, ``DateTimeField``, ``IntegerField``, ``ForeignKey`` or ``ManyToManyField``, for example:: - class PersonAdmin(ModelAdmin): + class PersonAdmin(admin.ModelAdmin): list_filter = ('is_staff', 'company') Field names in ``list_filter`` can also span relations using the ``__`` lookup, for example:: - class PersonAdmin(UserAdmin): + class PersonAdmin(admin.UserAdmin): list_filter = ('company__name',) * a class inheriting from ``django.contrib.admin.SimpleListFilter``, @@ -650,10 +693,10 @@ subclass:: from datetime import date + from django.contrib import admin from django.utils.translation import ugettext_lazy as _ - from django.contrib.admin import SimpleListFilter - class DecadeBornListFilter(SimpleListFilter): + class DecadeBornListFilter(admin.SimpleListFilter): # Human-readable title which will be displayed in the # right admin sidebar just above the filter options. title = _('decade born') @@ -689,7 +732,7 @@ subclass:: return queryset.filter(birthday__gte=date(1990, 1, 1), birthday__lte=date(1999, 12, 31)) - class PersonAdmin(ModelAdmin): + class PersonAdmin(admin.ModelAdmin): list_filter = (DecadeBornListFilter,) .. note:: @@ -732,11 +775,9 @@ subclass:: element is a class inheriting from ``django.contrib.admin.FieldListFilter``, for example:: - from django.contrib.admin import BooleanFieldListFilter - - class PersonAdmin(ModelAdmin): + class PersonAdmin(admin.ModelAdmin): list_filter = ( - ('is_staff', BooleanFieldListFilter), + ('is_staff', admin.BooleanFieldListFilter), ) .. note:: @@ -746,7 +787,7 @@ subclass:: It is possible to specify a custom template for rendering a list filter:: - class FilterWithCustomTemplate(SimpleListFilter): + class FilterWithCustomTemplate(admin.SimpleListFilter): template = "custom_template.html" See the default template provided by django (``admin/filter.html``) for @@ -771,12 +812,24 @@ subclass:: the list of objects on the admin change list page. This can save you a bunch of database queries. - The value should be either ``True`` or ``False``. Default is ``False``. + .. versionchanged:: dev + + The value should be either a boolean, a list or a tuple. Default is + ``False``. + + When value is ``True``, ``select_related()`` will always be called. When + value is set to ``False``, Django will look at ``list_display`` and call + ``select_related()`` if any ``ForeignKey`` is present. - Note that Django will use - :meth:`~django.db.models.query.QuerySet.select_related`, - regardless of this setting if one of the ``list_display`` fields is a - ``ForeignKey``. + If you need more fine-grained control, use a tuple (or list) as value for + ``list_select_related``. Empty tuple will prevent Django from calling + ``select_related`` at all. Any other tuple will be passed directly to + ``select_related`` as parameters. For example:: + + class ArticleAdmin(admin.ModelAdmin): + list_select_related = ('author', 'category') + + will call ``select_related('author', 'category')``. .. attribute:: ModelAdmin.ordering @@ -876,10 +929,11 @@ subclass:: the admin interface to provide feedback on the status of the objects being edited, for example:: + from django.contrib import admin from django.utils.html import format_html_join from django.utils.safestring import mark_safe - class PersonAdmin(ModelAdmin): + class PersonAdmin(admin.ModelAdmin): readonly_fields = ('address_report',) def address_report(self, instance): @@ -984,6 +1038,10 @@ subclass:: Performs a full-text match. This is like the default search method but uses an index. Currently this is only available for MySQL. + If you need to customize search you can use + :meth:`ModelAdmin.get_search_results` to provide additional or alternate + search behavior. + Custom template options ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1038,6 +1096,8 @@ templates used by the :class:`ModelAdmin` views: For example to attach ``request.user`` to the object prior to saving:: + from django.contrib import admin + class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.user = request.user @@ -1071,7 +1131,7 @@ templates used by the :class:`ModelAdmin` views: is expected to return a ``list`` or ``tuple`` for ordering similar to the :attr:`ordering` attribute. For example:: - class PersonAdmin(ModelAdmin): + class PersonAdmin(admin.ModelAdmin): def get_ordering(self, request): if request.user.is_superuser: @@ -1079,6 +1139,39 @@ templates used by the :class:`ModelAdmin` views: else: return ['name'] +.. method:: ModelAdmin.get_search_results(self, request, queryset, search_term) + + .. versionadded:: 1.6 + + The ``get_search_results`` method modifies the list of objects displayed in + to those that match the provided search term. It accepts the request, a + queryset that applies the current filters, and the user-provided search term. + It returns a tuple containing a queryset modified to implement the search, and + a boolean indicating if the results may contain duplicates. + + The default implementation searches the fields named in :attr:`ModelAdmin.search_fields`. + + This method may be overridden with your own custom search method. For + example, you might wish to search by an integer field, or use an external + tool such as Solr or Haystack. You must establish if the queryset changes + implemented by your search method may introduce duplicates into the results, + and return ``True`` in the second element of the return value. + + For example, to enable search by integer field, you could use:: + + class PersonAdmin(admin.ModelAdmin): + list_display = ('name', 'age') + search_fields = ('name',) + + def get_search_results(self, request, queryset, search_term): + queryset, use_distinct = super(PersonAdmin, self).get_search_results(request, queryset, search_term) + try: + search_term_as_int = int(search_term) + queryset |= self.model.objects.filter(age=search_term_as_int) + except: + pass + return queryset, use_distinct + .. method:: ModelAdmin.save_related(self, request, form, formsets, change) The ``save_related`` method is given the ``HttpRequest``, the parent @@ -1298,6 +1391,8 @@ templates used by the :class:`ModelAdmin` views: Returns a :class:`~django.forms.ModelForm` class for use in the ``Formset`` on the changelist page. To use a custom form, for example:: + from django import forms + class MyForm(forms.ModelForm): pass @@ -1539,6 +1634,8 @@ information. The admin interface has the ability to edit models on the same page as a parent model. These are called inlines. Suppose you have these two models:: + from django.db import models + class Author(models.Model): name = models.CharField(max_length=100) @@ -1549,6 +1646,8 @@ information. You can edit the books authored by an author on the author page. You add inlines to a model by specifying them in a ``ModelAdmin.inlines``:: + from django.contrib import admin + class BookInline(admin.TabularInline): model = Book @@ -1629,6 +1728,11 @@ The ``InlineModelAdmin`` class adds: The dynamic link will not appear if the number of currently displayed forms exceeds ``max_num``, or if the user does not have JavaScript enabled. + .. versionadded:: 1.6 + + :meth:`InlineModelAdmin.get_extra` also allows you to customize the number + of extra forms. + .. _ref-contrib-admin-inline-max-num: .. attribute:: InlineModelAdmin.max_num @@ -1637,6 +1741,11 @@ The ``InlineModelAdmin`` class adds: doesn't directly correlate to the number of objects, but can if the value is small enough. See :ref:`model-formsets-max-num` for more information. + .. versionadded:: 1.6 + + :meth:`InlineModelAdmin.get_max_num` also allows you to customize the + maximum number of extra forms. + .. attribute:: InlineModelAdmin.raw_id_fields By default, Django's admin uses a select-box interface (<select>) for @@ -1676,12 +1785,55 @@ The ``InlineModelAdmin`` class adds: Returns a ``BaseInlineFormSet`` class for use in admin add/change views. See the example for :class:`ModelAdmin.get_formsets`. +.. method:: InlineModelAdmin.get_extra(self, request, obj=None, **kwargs) + + .. versionadded:: 1.6 + + Returns the number of extra inline forms to use. By default, returns the + :attr:`InlineModelAdmin.extra` attribute. + + Override this method to programmatically determine the number of extra + inline forms. For example, this may be based on the model instance + (passed as the keyword argument ``obj``):: + + class BinaryTreeAdmin(admin.TabularInline): + model = BinaryTree + + def get_extra(self, request, obj=None, **kwargs): + extra = 2 + if obj: + return extra - obj.binarytree_set.count() + return extra + +.. method:: InlineModelAdmin.get_max_num(self, request, obj=None, **kwargs) + + .. versionadded:: 1.6 + + Returns the maximum number of extra inline forms to use. By default, + returns the :attr:`InlineModelAdmin.max_num` attribute. + + Override this method to programmatically determine the maximum number of + inline forms. For example, this may be based on the model instance + (passed as the keyword argument ``obj``):: + + class BinaryTreeAdmin(admin.TabularInline): + model = BinaryTree + + def get_max_num(self, request, obj=None, **kwargs): + max_num = 10 + if obj.parent: + return max_num - 5 + return max_num + + Working with a model with two or more foreign keys to the same parent model --------------------------------------------------------------------------- It is sometimes possible to have more than one foreign key to the same model. Take this model for instance:: + from django.db import models + class Friendship(models.Model): to_person = models.ForeignKey(Person, related_name="friends") from_person = models.ForeignKey(Person, related_name="from_friends") @@ -1690,6 +1842,9 @@ If you wanted to display an inline on the ``Person`` admin add/change pages you need to explicitly define the foreign key since it is unable to do so automatically:: + from django.contrib import admin + from myapp.models import Friendship + class FriendshipInline(admin.TabularInline): model = Friendship fk_name = "to_person" @@ -1712,6 +1867,8 @@ widgets with inlines. Suppose we have the following models:: + from django.db import models + class Person(models.Model): name = models.CharField(max_length=128) @@ -1722,6 +1879,8 @@ Suppose we have the following models:: If you want to display many-to-many relations using an inline, you can do so by defining an ``InlineModelAdmin`` object for the relationship:: + from django.contrib import admin + class MembershipInline(admin.TabularInline): model = Group.members.through @@ -1768,6 +1927,8 @@ However, we still want to be able to edit that information inline. Fortunately, this is easy to do with inline admin models. Suppose we have the following models:: + from django.db import models + class Person(models.Model): name = models.CharField(max_length=128) @@ -1816,6 +1977,8 @@ Using generic relations as an inline It is possible to use an inline with generically related objects. Let's say you have the following models:: + from django.db import models + class Image(models.Model): image = models.ImageField(upload_to="images") content_type = models.ForeignKey(ContentType) diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt index 4fa119bc70..de9c5dcbd6 100644 --- a/docs/ref/contrib/contenttypes.txt +++ b/docs/ref/contrib/contenttypes.txt @@ -303,6 +303,15 @@ model: :class:`~django.contrib.contenttypes.generic.GenericForeignKey` will look for. + .. attribute:: GenericForeignKey.for_concrete_model + + .. versionadded:: 1.6 + + If ``False``, the field will be able to reference proxy models. Default + is ``True``. This mirrors the ``for_concrete_model`` argument to + :meth:`~django.contrib.contenttypes.models.ContentTypeManager.get_for_model`. + + .. admonition:: Primary key type compatibility The "object_id" field doesn't have to be the same type as the @@ -329,7 +338,7 @@ model: .. admonition:: Serializing references to ``ContentType`` objects If you're serializing data (for example, when generating - :class:`~django.test.TestCase.fixtures`) from a model that implements + :class:`~django.test.TransactionTestCase.fixtures`) from a model that implements generic relations, you should probably be using a natural key to uniquely identify related :class:`~django.contrib.contenttypes.models.ContentType` objects. See :ref:`natural keys<topics-serialization-natural-keys>` and @@ -492,7 +501,7 @@ information. Subclasses of :class:`GenericInlineModelAdmin` with stacked and tabular layouts, respectively. -.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False) +.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True) Returns a ``GenericInlineFormSet`` using :func:`~django.forms.models.modelformset_factory`. @@ -502,3 +511,9 @@ information. are similar to those documented in :func:`~django.forms.models.modelformset_factory` and :func:`~django.forms.models.inlineformset_factory`. + + .. versionadded:: 1.6 + + The ``for_concrete_model`` argument corresponds to the + :class:`~django.contrib.contenttypes.generic.GenericForeignKey.for_concrete_model` + argument on ``GenericForeignKey``. diff --git a/docs/ref/contrib/csrf.txt b/docs/ref/contrib/csrf.txt index 968ef0b07b..f8b3cf2646 100644 --- a/docs/ref/contrib/csrf.txt +++ b/docs/ref/contrib/csrf.txt @@ -120,7 +120,7 @@ Acquiring the token is straightforward: var csrftoken = getCookie('csrftoken'); The above code could be simplified by using the `jQuery cookie plugin -<http://plugins.jquery.com/project/Cookie>`_ to replace ``getCookie``: +<http://plugins.jquery.com/cookie/>`_ to replace ``getCookie``: .. code-block:: javascript @@ -384,6 +384,7 @@ Utilities the middleware. Example:: from django.views.decorators.csrf import csrf_exempt + from django.http import HttpResponse @csrf_exempt def my_view(request): diff --git a/docs/ref/contrib/formtools/form-preview.txt b/docs/ref/contrib/formtools/form-preview.txt index 011e72c2e0..b86cc4dc90 100644 --- a/docs/ref/contrib/formtools/form-preview.txt +++ b/docs/ref/contrib/formtools/form-preview.txt @@ -53,6 +53,7 @@ How to use ``FormPreview`` overrides the ``done()`` method:: from django.contrib.formtools.preview import FormPreview + from django.http import HttpResponseRedirect from myapp.models import SomeModel class SomeModelFormPreview(FormPreview): diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt index f85ae8356d..7795a32c09 100644 --- a/docs/ref/contrib/formtools/form-wizard.txt +++ b/docs/ref/contrib/formtools/form-wizard.txt @@ -420,8 +420,10 @@ Advanced ``WizardView`` methods .. method:: WizardView.get_form(step=None, data=None, files=None) This method constructs the form for a given ``step``. If no ``step`` is - defined, the current step will be determined automatically. - The method gets three arguments: + defined, the current step will be determined automatically. If you override + ``get_form``, however, you will need to set ``step`` yourself using + ``self.steps.current`` as in the example below. The method gets three + arguments: * ``step`` -- The step for which the form instance should be generated. * ``data`` -- Gets passed to the form's data argument @@ -433,6 +435,11 @@ Advanced ``WizardView`` methods def get_form(self, step=None, data=None, files=None): form = super(MyWizard, self).get_form(step, data, files) + + # determine the step if not given + if step is None: + step = self.steps.current + if step == '1': form.user = self.request.user return form diff --git a/docs/ref/contrib/gis/geoip.txt b/docs/ref/contrib/gis/geoip.txt index 2444849a19..b6aca6b211 100644 --- a/docs/ref/contrib/gis/geoip.txt +++ b/docs/ref/contrib/gis/geoip.txt @@ -8,8 +8,7 @@ Geolocation with GeoIP :synopsis: High-level Python interface for MaxMind's GeoIP C library. The :class:`GeoIP` object is a ctypes wrapper for the -`MaxMind GeoIP C API`__. [#]_ This interface is a BSD-licensed alternative -to the GPL-licensed `Python GeoIP`__ interface provided by MaxMind. +`MaxMind GeoIP C API`__. [#]_ In order to perform IP-based geolocation, the :class:`GeoIP` object requires the GeoIP C libary and either the GeoIP `Country`__ or `City`__ @@ -20,7 +19,6 @@ you set :setting:`GEOIP_PATH` with in your settings. See the example and reference below for more details. __ http://www.maxmind.com/app/c -__ http://www.maxmind.com/app/python __ http://www.maxmind.com/app/country __ http://www.maxmind.com/app/city __ http://www.maxmind.com/download/geoip/database/ diff --git a/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh b/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh index 081b5f2656..67c82a8b25 100755 --- a/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh +++ b/docs/ref/contrib/gis/install/create_template_postgis-1.5.sh @@ -1,9 +1,15 @@ #!/usr/bin/env bash -POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib/postgis-1.5 +if [[ `uname -r | grep el6` ]]; then + POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib/postgis + POSTGIS_SQL_FILE=$POSTGIS_SQL_PATH/postgis-64.sql +else + POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib/postgis-1.5 + POSTGIS_SQL_FILE=$POSTGIS_SQL_PATH/postgis.sql +fi createdb -E UTF8 template_postgis # Create the template spatial database. createlang -d template_postgis plpgsql # Adding PLPGSQL language support. psql -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';" -psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis.sql # Loading the PostGIS SQL routines +psql -d template_postgis -f $POSTGIS_SQL_FILE # Loading the PostGIS SQL routines psql -d template_postgis -f $POSTGIS_SQL_PATH/spatial_ref_sys.sql psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;" # Enabling users to alter spatial tables. psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;" diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt index 0a376bca18..608c37bb7f 100644 --- a/docs/ref/contrib/messages.txt +++ b/docs/ref/contrib/messages.txt @@ -373,4 +373,3 @@ behavior: * :setting:`MESSAGE_LEVEL` * :setting:`MESSAGE_STORAGE` * :setting:`MESSAGE_TAGS` -* :ref:`SESSION_COOKIE_DOMAIN<messages-session_cookie_domain>` diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt index d37ee83378..56a15cb9e0 100644 --- a/docs/ref/contrib/sitemaps.txt +++ b/docs/ref/contrib/sitemaps.txt @@ -280,6 +280,46 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using both:: .. _URLconf: ../url_dispatch/ +Sitemap for static views +======================== + +Often you want the search engine crawlers to index views which are neither +object detail pages nor flatpages. The solution is to explicitly list URL +names for these views in ``items`` and call +:func:`~django.core.urlresolvers.reverse` in the ``location`` method of +the sitemap. For example:: + + # sitemaps.py + from django.contrib import sitemaps + from django.core.urlresolvers import reverse + + class StaticViewSitemap(sitemaps.Sitemap): + priority = 0.5 + changefreq = 'daily' + + def items(self): + return ['main', 'about', 'license'] + + def location(self, item): + return reverse(item) + + # urls.py + from django.conf.urls import patterns, url + from .sitemaps import StaticViewSitemap + + sitemaps = { + 'static': StaticViewSitemap, + } + + urlpatterns = patterns('', + url(r'^$', 'views.main', name='main'), + url(r'^about/$', 'views.about', name='about'), + url(r'^license/$', 'views.license', name='license'), + # ... + url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}) + ) + + Creating a sitemap index ======================== diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index 02159c415b..51d038d187 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -137,25 +137,29 @@ into those elements. See `a complex example`_ below that uses a description template. - There is also a way to pass additional information to title and description - templates, if you need to supply more than the two variables mentioned - before. You can provide your implementation of ``get_context_data`` method - in your Feed subclass. For example:: + .. method:: Feed.get_context_data(self, **kwargs) - from mysite.models import Article - from django.contrib.syndication.views import Feed + .. versionadded:: 1.6 - class ArticlesFeed(Feed): - title = "My articles" - description_template = "feeds/articles.html" + There is also a way to pass additional information to title and description + templates, if you need to supply more than the two variables mentioned + before. You can provide your implementation of ``get_context_data`` method + in your ``Feed`` subclass. For example:: - def items(self): - return Article.objects.order_by('-pub_date')[:5] + from mysite.models import Article + from django.contrib.syndication.views import Feed - def get_context_data(self, **kwargs): - context = super(ArticlesFeed, self).get_context_data(**kwargs) - context['foo'] = 'bar' - return context + class ArticlesFeed(Feed): + title = "My articles" + description_template = "feeds/articles.html" + + def items(self): + return Article.objects.order_by('-pub_date')[:5] + + def get_context_data(self, **kwargs): + context = super(ArticlesFeed, self).get_context_data(**kwargs) + context['foo'] = 'bar' + return context And the template: diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 7555acaaba..a648ac1709 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -135,16 +135,17 @@ configuration in :setting:`DATABASES`:: Since Django 1.6, autocommit is turned on by default. This configuration is ignored and can be safely removed. +.. _database-isolation-level: + Isolation level --------------- .. versionadded:: 1.6 Like PostgreSQL itself, Django defaults to the ``READ COMMITTED`` `isolation -level <postgresql-isolation-levels>`_. If you need a higher isolation level -such as ``REPEATABLE READ`` or ``SERIALIZABLE``, set it in the -:setting:`OPTIONS` part of your database configuration in -:setting:`DATABASES`:: +level`_. If you need a higher isolation level such as ``REPEATABLE READ`` or +``SERIALIZABLE``, set it in the :setting:`OPTIONS` part of your database +configuration in :setting:`DATABASES`:: import psycopg2.extensions @@ -161,7 +162,7 @@ such as ``REPEATABLE READ`` or ``SERIALIZABLE``, set it in the handle exceptions raised on serialization failures. This option is designed for advanced uses. -.. _postgresql-isolation-levels: http://www.postgresql.org/docs/current/static/transaction-iso.html +.. _isolation level: http://www.postgresql.org/docs/current/static/transaction-iso.html Indexes for ``varchar`` and ``text`` columns -------------------------------------------- @@ -803,5 +804,5 @@ the support channels provided by each 3rd party project. .. _IBM DB2: http://code.google.com/p/ibm-db/ .. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/ .. _Firebird: http://code.google.com/p/django-firebird/ -.. _ODBC: http://code.google.com/p/django-pyodbc/ +.. _ODBC: https://github.com/aurorasoftware/django-pyodbc/ .. _ADSDB: http://code.google.com/p/adsdb-django/ diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 2f2880679c..e21e3d2766 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -227,6 +227,15 @@ a natural key definition. If you are dumping ``contrib.auth`` ``Permission`` objects or ``contrib.contenttypes`` ``ContentType`` objects, you should probably be using this flag. +.. versionadded:: 1.6 + +.. django-admin-option:: --pks + +By default, ``dumpdata`` will output all the records of the model, but +you can use the ``--pks`` option to specify a comma seperated list of +primary keys on which to filter. This is only available when dumping +one model. + flush ----- @@ -1314,6 +1323,8 @@ clearsessions .. django-admin:: clearsessions +.. versionadded:: 1.5 + Can be run as a cron job or directly to clean out expired sessions. ``django.contrib.sitemaps`` diff --git a/docs/ref/exceptions.txt b/docs/ref/exceptions.txt index f9a1715180..b15bbea8fa 100644 --- a/docs/ref/exceptions.txt +++ b/docs/ref/exceptions.txt @@ -44,9 +44,24 @@ SuspiciousOperation ------------------- .. exception:: SuspiciousOperation - The :exc:`SuspiciousOperation` exception is raised when a user has performed - an operation that should be considered suspicious from a security perspective, - such as tampering with a session cookie. + The :exc:`SuspiciousOperation` exception is raised when a user has + performed an operation that should be considered suspicious from a security + perspective, such as tampering with a session cookie. Subclasses of + SuspiciousOperation include: + + * DisallowedHost + * DisallowedModelAdminLookup + * DisallowedRedirect + * InvalidSessionKey + * SuspiciousFileOperation + * SuspiciousMultipartForm + * SuspiciousSession + * WizardViewCookieModified + + If a ``SuspiciousOperation`` exception reaches the WSGI handler level it is + logged at the ``Error`` level and results in + a :class:`~django.http.HttpResponseBadRequest`. See the :doc:`logging + documentation </topics/logging/>` for more information. PermissionDenied ---------------- @@ -137,10 +152,16 @@ The Django wrappers for database exceptions behave exactly the same as the underlying database exceptions. See :pep:`249`, the Python Database API Specification v2.0, for further information. +As per :pep:`3134`, a ``__cause__`` attribute is set with the original +(underlying) database exception, allowing access to any additional +information provided. (Note that this attribute is available under +both Python 2 and Python 3, although :pep:`3134` normally only applies +to Python 3.) + .. versionchanged:: 1.6 Previous version of Django only wrapped ``DatabaseError`` and - ``IntegrityError``. + ``IntegrityError``, and did not provide ``__cause__``. .. exception:: models.ProtectedError diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt index 34ed2e493e..67e3aab712 100644 --- a/docs/ref/forms/api.txt +++ b/docs/ref/forms/api.txt @@ -154,6 +154,7 @@ you include ``initial`` when instantiating the ``Form``, then the latter at the field level and at the form instance level, and the latter gets precedence:: + >>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(initial='class') ... url = forms.URLField() @@ -238,6 +239,7 @@ When the ``Form`` is valid, ``cleaned_data`` will include a key and value for fields. In this example, the data dictionary doesn't include a value for the ``nick_name`` field, but ``cleaned_data`` includes it, with an empty value:: + >>> from django.forms import Form >>> class OptionalPersonForm(Form): ... first_name = CharField() ... last_name = CharField() @@ -327,54 +329,54 @@ a form object, and each rendering method returns a Unicode object. .. method:: Form.as_p - ``as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>`` - containing one field:: +``as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>`` +containing one field:: - >>> f = ContactForm() - >>> f.as_p() - u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>' - >>> print(f.as_p()) - <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p> - <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p> - <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></p> - <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> + >>> f = ContactForm() + >>> f.as_p() + u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>' + >>> print(f.as_p()) + <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p> + <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p> + <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></p> + <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> ``as_ul()`` ~~~~~~~~~~~ .. method:: Form.as_ul - ``as_ul()`` renders the form as a series of ``<li>`` tags, with each - ``<li>`` containing one field. It does *not* include the ``<ul>`` or - ``</ul>``, so that you can specify any HTML attributes on the ``<ul>`` for - flexibility:: +``as_ul()`` renders the form as a series of ``<li>`` tags, with each +``<li>`` containing one field. It does *not* include the ``<ul>`` or +``</ul>``, so that you can specify any HTML attributes on the ``<ul>`` for +flexibility:: - >>> f = ContactForm() - >>> f.as_ul() - u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>' - >>> print(f.as_ul()) - <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li> - <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li> - <li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></li> - <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li> + >>> f = ContactForm() + >>> f.as_ul() + u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>' + >>> print(f.as_ul()) + <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li> + <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li> + <li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></li> + <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li> ``as_table()`` ~~~~~~~~~~~~~~ .. method:: Form.as_table - Finally, ``as_table()`` outputs the form as an HTML ``<table>``. This is - exactly the same as ``print``. In fact, when you ``print`` a form object, - it calls its ``as_table()`` method behind the scenes:: +Finally, ``as_table()`` outputs the form as an HTML ``<table>``. This is +exactly the same as ``print``. In fact, when you ``print`` a form object, +it calls its ``as_table()`` method behind the scenes:: - >>> f = ContactForm() - >>> f.as_table() - u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>' - >>> print(f.as_table()) - <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> - <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> - <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr> - <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr> + >>> f = ContactForm() + >>> f.as_table() + u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>' + >>> print(f.as_table()) + <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> + <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> + <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr> + <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr> Styling required or erroneous form rows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -391,6 +393,8 @@ attributes to required rows or to rows with errors: simply set the :attr:`Form.error_css_class` and/or :attr:`Form.required_css_class` attributes:: + from django.forms import Form + class ContactForm(Form): error_css_class = 'error' required_css_class = 'required' @@ -621,23 +625,23 @@ For a field's list of errors, access the field's ``errors`` attribute. .. attribute:: BoundField.errors - A list-like object that is displayed as an HTML ``<ul class="errorlist">`` - when printed:: +A list-like object that is displayed as an HTML ``<ul class="errorlist">`` +when printed:: - >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} - >>> f = ContactForm(data, auto_id=False) - >>> print(f['message']) - <input type="text" name="message" /> - >>> f['message'].errors - [u'This field is required.'] - >>> print(f['message'].errors) - <ul class="errorlist"><li>This field is required.</li></ul> - >>> f['subject'].errors - [] - >>> print(f['subject'].errors) + >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} + >>> f = ContactForm(data, auto_id=False) + >>> print(f['message']) + <input type="text" name="message" /> + >>> f['message'].errors + [u'This field is required.'] + >>> print(f['message'].errors) + <ul class="errorlist"><li>This field is required.</li></ul> + >>> f['subject'].errors + [] + >>> print(f['subject'].errors) - >>> str(f['subject'].errors) - '' + >>> str(f['subject'].errors) + '' .. method:: BoundField.label_tag(contents=None, attrs=None) @@ -779,6 +783,7 @@ example, ``BeatleForm`` subclasses both ``PersonForm`` and ``InstrumentForm`` (in that order), and its field list includes the fields from the parent classes:: + >>> from django.forms import Form >>> class PersonForm(Form): ... first_name = CharField() ... last_name = CharField() diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt index 8e1a4b34d1..69e3aa71ad 100644 --- a/docs/ref/forms/fields.txt +++ b/docs/ref/forms/fields.txt @@ -48,6 +48,7 @@ By default, each ``Field`` class assumes the value is required, so if you pass an empty value -- either ``None`` or the empty string (``""``) -- then ``clean()`` will raise a ``ValidationError`` exception:: + >>> from django import forms >>> f = forms.CharField() >>> f.clean('foo') u'foo' @@ -107,6 +108,7 @@ behavior doesn't result in an adequate label. Here's a full example ``Form`` that implements ``label`` for two of its fields. We've specified ``auto_id=False`` to simplify the output:: + >>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(label='Your name') ... url = forms.URLField(label='Your Web site', required=False) @@ -130,6 +132,7 @@ To specify dynamic initial data, see the :attr:`Form.initial` parameter. The use-case for this is when you want to display an "empty" form in which a field is initialized to a particular value. For example:: + >>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(initial='Your name') ... url = forms.URLField(initial='http://') @@ -205,6 +208,7 @@ methods (e.g., ``as_ul()``). Here's a full example ``Form`` that implements ``help_text`` for two of its fields. We've specified ``auto_id=False`` to simplify the output:: + >>> from django import forms >>> class HelpTextContactForm(forms.Form): ... subject = forms.CharField(max_length=100, help_text='100 characters max.') ... message = forms.CharField() @@ -236,6 +240,7 @@ The ``error_messages`` argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override. For example, here is the default error message:: + >>> from django import forms >>> generic = forms.CharField() >>> generic.clean('') Traceback (most recent call last): @@ -853,6 +858,7 @@ Slightly complex built-in ``Field`` classes The list of fields that should be used to validate the field's value (in the order in which they are provided). + >>> from django.forms import ComboField >>> f = ComboField(fields=[CharField(max_length=20), EmailField()]) >>> f.clean('test@example.com') u'test@example.com' @@ -1001,6 +1007,8 @@ objects (in the case of ``ModelMultipleChoiceField``) into the object, and should return a string suitable for representing it. For example:: + from django.forms import ModelChoiceField + class MyModelChoiceField(ModelChoiceField): def label_from_instance(self, obj): return "My Object #%i" % obj.id diff --git a/docs/ref/forms/models.txt b/docs/ref/forms/models.txt index 9b3480758a..b54056af0c 100644 --- a/docs/ref/forms/models.txt +++ b/docs/ref/forms/models.txt @@ -5,7 +5,7 @@ Model Form Functions .. module:: django.forms.models :synopsis: Django's functions for building model forms and formsets. -.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None, widgets=None) +.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None, widgets=None, localized_fields=None) Returns a :class:`~django.forms.ModelForm` class for the given ``model``. You can optionally pass a ``form`` argument to use as a starting point for @@ -20,6 +20,8 @@ Model Form Functions ``widgets`` is a dictionary of model field names mapped to a widget. + ``localized_fields`` is a list of names of fields which should be localized. + ``formfield_callback`` is a callable that takes a model field and returns a form field. @@ -31,14 +33,16 @@ Model Form Functions ``fields`` or ``exclude``, or the corresponding attributes on the form's inner ``Meta`` class. See :ref:`modelforms-selecting-fields` for more information. Omitting any definition of the fields to use will result in all - fields being used, but this behaviour is deprecated. + fields being used, but this behavior is deprecated. + + The ``localized_fields`` parameter was added. -.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False) +.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None) Returns a ``FormSet`` class for the given ``model`` class. Arguments ``model``, ``form``, ``fields``, ``exclude``, - ``formfield_callback`` and ``widgets`` are all passed through to + ``formfield_callback``, ``widgets`` and ``localized_fields`` are all passed through to :func:`~django.forms.models.modelform_factory`. Arguments ``formset``, ``extra``, ``max_num``, ``can_order``, @@ -50,9 +54,9 @@ Model Form Functions .. versionchanged:: 1.6 - The ``widgets`` and the ``validate_max`` parameters were added. + The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added. -.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False) +.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False, localized_fields=None) Returns an ``InlineFormSet`` using :func:`modelformset_factory` with defaults of ``formset=BaseInlineFormSet``, ``can_delete=True``, and @@ -65,4 +69,4 @@ Model Form Functions .. versionchanged:: 1.6 - The ``widgets`` and the ``validate_max`` parameters were added. + The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added. diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt index 3aaa69b6ea..87c9764f64 100644 --- a/docs/ref/forms/validation.txt +++ b/docs/ref/forms/validation.txt @@ -183,6 +183,9 @@ the ``default_validators`` attribute. Simple validators can be used to validate values inside the field, let's have a look at Django's ``SlugField``:: + from django.forms import CharField + from django.core import validators + class SlugField(CharField): default_validators = [validators.validate_slug] @@ -252,6 +255,8 @@ we want to make sure that the ``recipients`` field always contains the address don't want to put it into the general ``MultiEmailField`` class. Instead, we write a cleaning method that operates on the ``recipients`` field, like so:: + from django import forms + class ContactForm(forms.Form): # Everything as before. ... @@ -289,6 +294,8 @@ common method is to display the error at the top of the form. To create such an error, you can raise a ``ValidationError`` from the ``clean()`` method. For example:: + from django import forms + class ContactForm(forms.Form): # Everything as before. ... @@ -321,6 +328,8 @@ here and leaving it up to you and your designers to work out what works effectively in your particular situation. Our new code (replacing the previous sample) looks like this:: + from django import forms + class ContactForm(forms.Form): # Everything as before. ... diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt index 678f2e6949..0f6917d44c 100644 --- a/docs/ref/forms/widgets.txt +++ b/docs/ref/forms/widgets.txt @@ -201,6 +201,7 @@ foundation for custom widgets. .. code-block:: python + >>> from django import forms >>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name',}) >>> name.render('name', 'A name') u'<input title="Your name" type="text" name="name" value="A name" size="10" />' @@ -249,6 +250,8 @@ foundation for custom widgets. :class:`~datetime.datetime` value into a list with date and time split into two separate values:: + from django.forms import MultiWidget + class SplitDateTimeWidget(MultiWidget): # ... diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index 03885a2215..4898bab636 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -71,19 +71,6 @@ Adds a few conveniences for perfectionists: * Sends broken link notification emails to :setting:`MANAGERS` (see :doc:`/howto/error-reporting`). -View metadata middleware ------------------------- - -.. module:: django.middleware.doc - :synopsis: Middleware to help your app self-document. - -.. class:: XViewMiddleware - -Sends custom ``X-View`` HTTP headers to HEAD requests that come from IP -addresses defined in the :setting:`INTERNAL_IPS` setting. This is used by -Django's :doc:`automatic documentation system </ref/contrib/admin/admindocs>`. -Depends on :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`. - GZip middleware --------------- diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index 99ba78cb09..8146dfd341 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -80,9 +80,10 @@ If a field has ``blank=False``, the field will be required. .. attribute:: Field.choices -An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this -field. If this is given, the default form widget will be a select box with -these choices instead of the standard text field. +An iterable (e.g., a list or tuple) consisting itself of iterables of exactly +two items (e.g. ``[(A, B), (A, B) ...]``) to use as choices for this field. If +this is given, the default form widget will be a select box with these choices +instead of the standard text field. The first element in each tuple is the actual value to be stored, and the second element is the human-readable name. For example:: @@ -97,6 +98,8 @@ second element is the human-readable name. For example:: Generally, it's best to define choices inside a model class, and to define a suitably-named constant for each value:: + from django.db import models + class Student(models.Model): FRESHMAN = 'FR' SOPHOMORE = 'SO' @@ -290,7 +293,12 @@ records with the same ``title`` and ``pub_date``. Note that if you set this to point to a :class:`DateTimeField`, only the date portion of the field will be considered. -This is enforced by model validation but not at the database level. +This is enforced by :meth:`Model.validate_unique()` during model validation +but not at the database level. If any :attr:`~Field.unique_for_date` constraint +involves fields that are not part of a :class:`~django.forms.ModelForm` (for +example, if one of the fields is listed in ``exclude`` or has +:attr:`editable=False<Field.editable>`), :meth:`Model.validate_unique()` will +skip validation for that particular constraint. ``unique_for_month`` -------------------- @@ -365,7 +373,7 @@ to filter a queryset on a ``BinaryField`` value. Although you might think about storing files in the database, consider that it is bad design in 99% of the cases. This field is *not* a replacement for - proper :doc`static files </howto/static-files>` handling. + proper :doc:`static files </howto/static-files/index>` handling. ``BooleanField`` ---------------- @@ -889,7 +897,8 @@ The value ``0`` is accepted for backward compatibility reasons. .. class:: PositiveSmallIntegerField([**options]) Like a :class:`PositiveIntegerField`, but only allows values under a certain -(database-dependent) point. +(database-dependent) point. Values up to 32767 are safe in all databases +supported by Django. ``SlugField`` ------------- @@ -917,7 +926,8 @@ of some other value. You can do this automatically in the admin using .. class:: SmallIntegerField([**options]) Like an :class:`IntegerField`, but only allows values under a certain -(database-dependent) point. +(database-dependent) point. Values from -32768 to 32767 are safe in all databases +supported by Django. ``TextField`` ------------- @@ -994,12 +1004,15 @@ relationship with itself -- use ``models.ForeignKey('self')``. If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself:: + from django.db import models + class Car(models.Model): manufacturer = models.ForeignKey('Manufacturer') # ... class Manufacturer(models.Model): # ... + pass To refer to models defined in another application, you can explicitly specify a model with the full application label. For example, if the ``Manufacturer`` @@ -1132,6 +1145,9 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in necessary to avoid executing queries at the time your models.py is imported:: + from django.db import models + from django.contrib.auth.models import User + def get_sentinel_user(): return User.objects.get_or_create(username='deleted')[0] @@ -1204,6 +1220,8 @@ that control how the relationship functions. Only used in the definition of ManyToManyFields on self. Consider the following model:: + from django.db import models + class Person(models.Model): friends = models.ManyToManyField("self") diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt index b4b162a9ea..f989ff1bec 100644 --- a/docs/ref/models/instances.txt +++ b/docs/ref/models/instances.txt @@ -34,6 +34,8 @@ that, you need to :meth:`~Model.save()`. 1. Add a classmethod on the model class:: + from django.db import models + class Book(models.Model): title = models.CharField(max_length=100) @@ -105,6 +107,7 @@ individually. You'll need to call ``full_clean`` manually when you want to run one-step model validation for your own manually created models. For example:: + from django.core.exceptions import ValidationError try: article.full_clean() except ValidationError as e: @@ -132,6 +135,7 @@ automatically provide a value for a field, or to do validation that requires access to more than a single field:: def clean(self): + import datetime from django.core.exceptions import ValidationError # Don't allow draft entries to have a pub_date. if self.status == 'draft' and self.pub_date is not None: @@ -434,6 +438,8 @@ representation of the model from the ``__unicode__()`` method. For example:: + from django.db import models + class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @@ -460,6 +466,9 @@ Thus, you should return a nice, human-readable string for the object's The previous :meth:`~Model.__unicode__()` example could be similarly written using ``__str__()`` like this:: + from django.db import models + from django.utils.encoding import force_bytes + class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @@ -490,6 +499,7 @@ function is usually the best approach.) For example:: def get_absolute_url(self): + from django.core.urlresolvers import reverse return reverse('people.views.details', args=[str(self.id)]) One place Django uses ``get_absolute_url()`` is in the admin app. If an object diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt index 5f9316bd2a..90099d13a3 100644 --- a/docs/ref/models/options.txt +++ b/docs/ref/models/options.txt @@ -145,6 +145,12 @@ Django quotes column and table names behind the scenes. and a question has more than one answer, and the order of answers matters, you'd do this:: + from django.db import models + + class Question(models.Model): + text = models.TextField() + # ... + class Answer(models.Model): question = models.ForeignKey(Question) # ... diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt index ffada19082..2788143899 100644 --- a/docs/ref/models/querysets.txt +++ b/docs/ref/models/querysets.txt @@ -232,6 +232,7 @@ the model field that is being aggregated. For example, if you were manipulating a list of blogs, you may want to determine how many entries have been made in each blog:: + >>> from django.db.models import Count >>> q = Blog.objects.annotate(Count('entry')) # The name of the first blog >>> q[0].name @@ -544,6 +545,11 @@ It is an error to pass in ``flat`` when there is more than one field. If you don't pass any values to ``values_list()``, it will return all the fields in the model, in the order they were declared. +Note that this method returns a ``ValuesListQuerySet``. This class behaves +like a list. Most of the time this is enough, but if you require an actual +Python list object, you can simply call ``list()`` on it, which will evaluate +the queryset. + dates ~~~~~ @@ -694,6 +700,8 @@ And here's ``select_related`` lookup:: ``select_related()`` follows foreign keys as far as possible. If you have the following models:: + from django.db import models + class City(models.Model): # ... pass @@ -766,6 +774,13 @@ You can also refer to the reverse direction of a is defined. Instead of specifying the field name, use the :attr:`related_name <django.db.models.ForeignKey.related_name>` for the field on the related object. +.. versionadded:: 1.6 + +If you need to clear the list of related fields added by past calls of +``select_related`` on a ``QuerySet``, you can pass ``None`` as a parameter:: + + >>> without_relations = queryset.select_related(None) + .. deprecated:: 1.5 The ``depth`` parameter to ``select_related()`` has been deprecated. You should replace it with the use of the ``(*fields)`` listing specific @@ -809,6 +824,8 @@ that are supported by ``select_related``. It also supports prefetching of For example, suppose you have these models:: + from django.db import models + class Topping(models.Model): name = models.CharField(max_length=30) @@ -1333,8 +1350,12 @@ get_or_create .. method:: get_or_create(**kwargs) -A convenience method for looking up an object with the given kwargs, creating -one if necessary. +A convenience method for looking up an object with the given kwargs (may be +empty if your model has defaults for all fields), creating one if necessary. + +.. versionchanged:: 1.6 + + Older versions of Django required ``kwargs``. Returns a tuple of ``(object, created)``, where ``object`` is the retrieved or created object and ``created`` is a boolean specifying whether a new object was @@ -1399,6 +1420,41 @@ has a side effect on your data. For more, see `Safe methods`_ in the HTTP spec. .. _Safe methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 +.. warning:: + + You can use ``get_or_create()`` through :class:`~django.db.models.ManyToManyField` + attributes and reverse relations. In that case you will restrict the queries + inside the context of that relation. That could lead you to some integrity + problems if you don't use it consistently. + + Being the following models:: + + class Chapter(models.Model): + title = models.CharField(max_length=255, unique=True) + + class Book(models.Model): + title = models.CharField(max_length=256) + chapters = models.ManyToManyField(Chapter) + + You can use ``get_or_create()`` through Book's chapters field, but it only + fetches inside the context of that book:: + + >>> book = Book.objects.create(title="Ulysses") + >>> book.chapters.get_or_create(title="Telemachus") + (<Chapter: Telemachus>, True) + >>> book.chapters.get_or_create(title="Telemachus") + (<Chapter: Telemachus>, False) + >>> Chapter.objects.create(title="Chapter 1") + <Chapter: Chapter 1> + >>> book.chapters.get_or_create(title="Chapter 1") + # Raises IntegrityError + + This is happening because it's trying to get or create "Chapter 1" through the + book "Ulysses", but it can't do any of them: the relation can't fetch that + chapter because it isn't related to that book, but it can't create it either + because ``title`` field should be unique. + + bulk_create ~~~~~~~~~~~ @@ -1540,6 +1596,36 @@ earliest Works otherwise like :meth:`~django.db.models.query.QuerySet.latest` except the direction is changed. +first +~~~~~ +.. method:: first() + +.. versionadded:: 1.6 + +Returns the first object matched by the queryset, or ``None`` if there +is no matching object. If the ``QuerySet`` has no ordering defined, then the +queryset is automatically ordered by the primary key. + +Example:: + + p = Article.objects.order_by('title', 'pub_date').first() + +Note that ``first()`` is a convenience method, the following code sample is +equivalent to the above example:: + + try: + p = Article.objects.order_by('title', 'pub_date')[0] + except IndexError: + p = None + +last +~~~~ +.. method:: last() + +.. versionadded:: 1.6 + +Works like :meth:`first()`, but returns the last object in the queryset. + aggregate ~~~~~~~~~ @@ -1560,6 +1646,7 @@ aggregated. For example, when you are working with blog entries, you may want to know the number of authors that have contributed blog entries:: + >>> from django.db.models import Count >>> q = Blog.objects.aggregate(Count('entry')) {'entry__count': 16} @@ -2037,6 +2124,7 @@ Range test (inclusive). Example:: + import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date)) diff --git a/docs/ref/models/relations.txt b/docs/ref/models/relations.txt index c923961a19..ffebe37193 100644 --- a/docs/ref/models/relations.txt +++ b/docs/ref/models/relations.txt @@ -12,8 +12,11 @@ Related objects reference * The "other side" of a :class:`~django.db.models.ForeignKey` relation. That is:: + from django.db import models + class Reporter(models.Model): - ... + # ... + pass class Article(models.Model): reporter = models.ForeignKey(Reporter) @@ -24,7 +27,8 @@ Related objects reference * Both sides of a :class:`~django.db.models.ManyToManyField` relation:: class Topping(models.Model): - ... + # ... + pass class Pizza(models.Model): toppings = models.ManyToManyField(Topping) diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 2fac7f2f9c..578418b4ee 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -578,20 +578,27 @@ streaming response if (and only if) no middleware accesses the instantiated with an iterator. Django will consume and save the content of the iterator on first access. -Setting headers -~~~~~~~~~~~~~~~ +Setting header fields +~~~~~~~~~~~~~~~~~~~~~ -To set or remove a header in your response, treat it like a dictionary:: +To set or remove a header field in your response, treat it like a dictionary:: >>> response = HttpResponse() - >>> response['Cache-Control'] = 'no-cache' - >>> del response['Cache-Control'] + >>> response['Age'] = 120 + >>> del response['Age'] Note that unlike a dictionary, ``del`` doesn't raise ``KeyError`` if the header -doesn't exist. +field doesn't exist. + +For setting the ``Cache-Control`` and ``Vary`` header fields, it is recommended +to use the :func:`~django.utils.cache.patch_cache_control` and +:func:`~django.utils.cache.patch_vary_headers` methods from +:mod:`django.utils.cache`, since these fields can have multiple, comma-separated +values. The "patch" methods ensure that other values, e.g. added by a +middleware, are not removed. -HTTP headers cannot contain newlines. An attempt to set a header containing a -newline character (CR or LF) will raise ``BadHeaderError`` +HTTP header fields cannot contain newlines. An attempt to set a header field +containing a newline character (CR or LF) will raise ``BadHeaderError`` Telling the browser to treat the response as a file attachment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -616,7 +623,13 @@ Attributes .. attribute:: HttpResponse.status_code - The `HTTP Status code`_ for the response. + The `HTTP status code`_ for the response. + +.. attribute:: HttpResponse.reason_phrase + + .. versionadded:: 1.6 + + The HTTP reason phrase for the response. .. attribute:: HttpResponse.streaming @@ -628,7 +641,7 @@ Attributes Methods ------- -.. method:: HttpResponse.__init__(content='', content_type=None, status=200) +.. method:: HttpResponse.__init__(content='', content_type=None, status=200, reason=None) Instantiates an ``HttpResponse`` object with the given page content and content type. @@ -646,8 +659,12 @@ Methods Historically, this parameter was called ``mimetype`` (now deprecated). - ``status`` is the `HTTP Status code`_ for the response. + ``status`` is the `HTTP status code`_ for the response. + .. versionadded:: 1.6 + + ``reason`` is the HTTP response phrase. If not provided, a default phrase + will be used. .. method:: HttpResponse.__setitem__(header, value) @@ -727,8 +744,7 @@ Methods This method makes an :class:`HttpResponse` instance a file-like object. -.. _HTTP Status code: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 - +.. _HTTP status code: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10 .. _ref-httpresponse-subclasses: @@ -851,7 +867,13 @@ Attributes .. attribute:: HttpResponse.status_code - The `HTTP Status code`_ for the response. + The `HTTP status code`_ for the response. + +.. attribute:: HttpResponse.reason_phrase + + .. versionadded:: 1.6 + + The HTTP reason phrase for the response. .. attribute:: HttpResponse.streaming diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index eb470cdd14..ef52d3170c 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -280,6 +280,12 @@ CACHE_MIDDLEWARE_ANONYMOUS_ONLY Default: ``False`` +.. deprecated:: 1.6 + + This setting was largely ineffective because of using cookies for sessions + and CSRF. See the :doc:`Django 1.6 release notes</releases/1.6>` for more + information. + If the value of this setting is ``True``, only anonymous requests (i.e., not those made by a logged-in user) will be cached. Otherwise, the middleware caches every page that doesn't have GET or POST parameters. @@ -287,8 +293,6 @@ caches every page that doesn't have GET or POST parameters. If you set the value of this setting to ``True``, you should make sure you've activated ``AuthenticationMiddleware``. -See :doc:`/topics/cache`. - .. setting:: CACHE_MIDDLEWARE_KEY_PREFIX CACHE_MIDDLEWARE_KEY_PREFIX @@ -340,9 +344,9 @@ CSRF_COOKIE_HTTPONLY Default: ``False`` -Whether to use HttpOnly flag on the CSRF cookie. If this is set to ``True``, -client-side JavaScript will not to be able to access the CSRF cookie. See -:setting:`SESSION_COOKIE_HTTPONLY` for details on HttpOnly. +Whether to use ``HttpOnly`` flag on the CSRF cookie. If this is set to +``True``, client-side JavaScript will not to be able to access the CSRF cookie. +See :setting:`SESSION_COOKIE_HTTPONLY` for details on ``HttpOnly``. .. setting:: CSRF_COOKIE_NAME @@ -1239,7 +1243,7 @@ Default: ``()`` (Empty tuple) A tuple of IP addresses, as strings, that: * See debug comments, when :setting:`DEBUG` is ``True`` -* Receive X headers if the ``XViewMiddleware`` is installed (see +* Receive X headers in admindocs if the ``XViewMiddleware`` is installed (see :doc:`/topics/http/middleware`) .. setting:: LANGUAGE_CODE @@ -2227,6 +2231,9 @@ Controls where Django stores message data. Valid values are: See :ref:`message storage backends <message-storage-backends>` for more details. +The backends that use cookies -- ``CookieStorage`` and ``FallbackStorage`` -- +use the value of :setting:`SESSION_COOKIE_DOMAIN` when setting their cookies. + .. setting:: MESSAGE_TAGS MESSAGE_TAGS @@ -2258,18 +2265,6 @@ to override. See :ref:`message-displaying` above for more details. according to the values in the above :ref:`constants table <message-level-constants>`. -.. _messages-session_cookie_domain: - -SESSION_COOKIE_DOMAIN ---------------------- - -Default: ``None`` - -The storage backends that use cookies -- ``CookieStorage`` and -``FallbackStorage`` -- use the value of :setting:`SESSION_COOKIE_DOMAIN` in -setting their cookies. - - .. _settings-sessions: Sessions @@ -2320,7 +2315,7 @@ SESSION_COOKIE_HTTPONLY Default: ``True`` -Whether to use HTTPOnly flag on the session cookie. If this is set to +Whether to use ``HTTPOnly`` flag on the session cookie. If this is set to ``True``, client-side JavaScript will not to be able to access the session cookie. diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt index ca472bd60e..e7270e1957 100644 --- a/docs/ref/signals.txt +++ b/docs/ref/signals.txt @@ -360,6 +360,53 @@ Management signals Signals sent by :doc:`django-admin </ref/django-admin>`. +pre_syncdb +---------- + +.. data:: django.db.models.signals.pre_syncdb + :module: + +Sent by the :djadmin:`syncdb` command before it starts to install an +application. + +Any handlers that listen to this signal need to be written in a particular +place: a ``management`` module in one of your :setting:`INSTALLED_APPS`. If +handlers are registered anywhere else they may not be loaded by +:djadmin:`syncdb`. + +Arguments sent with this signal: + +``sender`` + The ``models`` module that was just installed. That is, if + :djadmin:`syncdb` just installed an app called ``"foo.bar.myapp"``, + ``sender`` will be the ``foo.bar.myapp.models`` module. + +``app`` + Same as ``sender``. + +``create_models`` + A list of the model classes from any app which :djadmin:`syncdb` plans to + create. + + +``verbosity`` + Indicates how much information manage.py is printing on screen. See + the :djadminopt:`--verbosity` flag for details. + + Functions which listen for :data:`pre_syncdb` should adjust what they + output to the screen based on the value of this argument. + +``interactive`` + If ``interactive`` is ``True``, it's safe to prompt the user to input + things on the command line. If ``interactive`` is ``False``, functions + which listen for this signal should not try to prompt for anything. + + For example, the :mod:`django.contrib.auth` app only prompts to create a + superuser when ``interactive`` is ``True``. + +``db`` + The alias of database on which a command will operate. + post_syncdb ----------- diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt index cdefe2fae8..4f34d150ed 100644 --- a/docs/ref/template-response.txt +++ b/docs/ref/template-response.txt @@ -215,6 +215,7 @@ re-rendered, you can re-evaluate the rendered content, and assign the content of the response manually:: # Set up a rendered TemplateResponse + >>> from django.template.response import TemplateResponse >>> t = TemplateResponse(request, 'original.html', {}) >>> t.render() >>> print(t.content) @@ -256,6 +257,8 @@ To define a post-render callback, just define a function that takes a single argument -- response -- and register that function with the template response:: + from django.template.response import TemplateResponse + def my_render_callback(response): # Do content-sensitive processing do_post_processing() diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index 677aa13cbb..160cdc7194 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -286,6 +286,7 @@ fully-populated dictionary to ``Context()``. But you can add and delete items from a ``Context`` object once it's been instantiated, too, using standard dictionary syntax:: + >>> from django.template import Context >>> c = Context({"foo": "bar"}) >>> c['foo'] 'bar' @@ -397,6 +398,9 @@ Also, you can give ``RequestContext`` a list of additional processors, using the optional, third positional argument, ``processors``. In this example, the ``RequestContext`` instance gets a ``ip_address`` variable:: + from django.http import HttpResponse + from django.template import RequestContext + def ip_address_processor(request): return {'ip_address': request.META['REMOTE_ADDR']} @@ -417,6 +421,9 @@ optional, third positional argument, ``processors``. In this example, the :func:`~django.shortcuts.render_to_response()`: a ``RequestContext`` instance. Your code might look like this:: + from django.shortcuts import render_to_response + from django.template import RequestContext + def some_view(request): # ... return render_to_response('my_template.html', diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 287fd4f59e..24eda2ce2c 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -862,6 +862,8 @@ above would result in the following output: * New York: 20,000,000 * India * Calcutta: 15,000,000 +* USA + * Chicago: 7,000,000 * Japan * Tokyo: 33,000,000 diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 14ae9aa9b8..d2ef945a2e 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -490,7 +490,7 @@ Atom1Feed Usually you should build up HTML using Django's templates to make use of its autoescape mechanism, using the utilities in :mod:`django.utils.safestring` -where appropriate. This module provides some additional low level utilitiesfor +where appropriate. This module provides some additional low level utilities for escaping HTML. .. function:: escape(text) @@ -564,7 +564,13 @@ escaping HTML. strip_tags(value) If ``value`` is ``"<b>Joel</b> <button>is</button> a <span>slug</span>"`` the - return value will be ``"Joel is a slug"``. + return value will be ``"Joel is a slug"``. Note that ``strip_tags`` result + may still contain unsafe HTML content, so you might use + :func:`~django.utils.html.escape` to make it a safe string. + + .. versionchanged:: 1.6 + + For improved safety, ``strip_tags`` is now parser-based. .. function:: remove_tags(value, tags) @@ -923,9 +929,21 @@ For a complete discussion on the usage of the following see the .. function:: now() - Returns an aware or naive :class:`~datetime.datetime` that represents the - current point in time when :setting:`USE_TZ` is ``True`` or ``False`` - respectively. + Returns a :class:`~datetime.datetime` that represents the + current point in time. Exactly what's returned depends on the value of + :setting:`USE_TZ`: + + * If :setting:`USE_TZ` is ``False``, this will be be a + :ref:`naive <naive_vs_aware_datetimes>` datetime (i.e. a datetime + without an associated timezone) that represents the current time + in the system's local timezone. + + * If :setting:`USE_TZ` is ``True``, this will be an + :ref:`aware <naive_vs_aware_datetimes>` datetime representing the + current time in UTC. Note that :func:`now` will always return + times in UTC regardless of the value of :setting:`TIME_ZONE`; + you can use :func:`localtime` to convert to a time in the current + time zone. .. function:: is_aware(value) diff --git a/docs/releases/1.3-alpha-1.txt b/docs/releases/1.3-alpha-1.txt index 42947d9a44..634e6afaf2 100644 --- a/docs/releases/1.3-alpha-1.txt +++ b/docs/releases/1.3-alpha-1.txt @@ -154,7 +154,7 @@ requests. These include: requests in tests. * A new test assertion -- - :meth:`~django.test.TestCase.assertNumQueries` -- making it + :meth:`~django.test.TransactionTestCase.assertNumQueries` -- making it easier to test the database activity associated with a view. diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt index 89cece941b..45ebb2f1fe 100644 --- a/docs/releases/1.3.txt +++ b/docs/releases/1.3.txt @@ -299,7 +299,7 @@ requests. These include: in tests. * A new test assertion -- - :meth:`~django.test.TestCase.assertNumQueries` -- making it + :meth:`~django.test.TransactionTestCase.assertNumQueries` -- making it easier to test the database activity associated with a view. * Support for lookups spanning relations in admin's diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 83a5f54fc7..a013665ad3 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -541,8 +541,8 @@ compare HTML directly with the new :meth:`~django.test.SimpleTestCase.assertHTMLEqual` and :meth:`~django.test.SimpleTestCase.assertHTMLNotEqual` assertions, or use the ``html=True`` flag with -:meth:`~django.test.TestCase.assertContains` and -:meth:`~django.test.TestCase.assertNotContains` to test whether the +:meth:`~django.test.SimpleTestCase.assertContains` and +:meth:`~django.test.SimpleTestCase.assertNotContains` to test whether the client's response contains a given HTML fragment. See the :ref:`assertions documentation <assertions>` for more. @@ -1093,8 +1093,8 @@ wild, because they would confuse browsers too. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's now possible to check whether a template was used within a block of -code with :meth:`~django.test.TestCase.assertTemplateUsed` and -:meth:`~django.test.TestCase.assertTemplateNotUsed`. And they +code with :meth:`~django.test.SimpleTestCase.assertTemplateUsed` and +:meth:`~django.test.SimpleTestCase.assertTemplateNotUsed`. And they can be used as a context manager:: with self.assertTemplateUsed('index.html'): diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index 98889254cd..6736af8c2d 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -78,10 +78,10 @@ location of tests. The previous runner ``models.py`` and ``tests.py`` modules of a Python package in :setting:`INSTALLED_APPS`. -The new runner (``django.test.runner.DjangoTestDiscoverRunner``) uses the test -discovery features built into unittest2 (the version of unittest in the Python -2.7+ standard library, and bundled with Django). With test discovery, tests can -be located in any module whose name matches the pattern ``test*.py``. +The new runner (``django.test.runner.DiscoverRunner``) uses the test discovery +features built into ``unittest2`` (the version of ``unittest`` in the +Python 2.7+ standard library, and bundled with Django). With test discovery, +tests can be located in any module whose name matches the pattern ``test*.py``. In addition, the test labels provided to ``./manage.py test`` to nominate specific tests to run must now be full Python dotted paths (or directory @@ -111,7 +111,7 @@ Django 1.6 adds support for savepoints in SQLite, with some :ref:`limitations ``BinaryField`` model field ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A new :class:`django.db.models.BinaryField` model field allows to store raw +A new :class:`django.db.models.BinaryField` model field allows storage of raw binary data in the database. GeoDjango form widgets @@ -127,13 +127,13 @@ Minor features * Authentication backends can raise ``PermissionDenied`` to immediately fail the authentication chain. -* The HttpOnly flag can be set on the CSRF cookie with +* The ``HttpOnly`` flag can be set on the CSRF cookie with :setting:`CSRF_COOKIE_HTTPONLY`. -* The ``assertQuerysetEqual()`` now checks for undefined order and raises - ``ValueError`` if undefined order is spotted. The order is seen as - undefined if the given ``QuerySet`` isn't ordered and there are more than - one ordered values to compare against. +* The :meth:`~django.test.TransactionTestCase.assertQuerysetEqual` now checks + for undefined order and raises :exc:`~exceptions.ValueError` if undefined + order is spotted. The order is seen as undefined if the given ``QuerySet`` + isn't ordered and there are more than one ordered values to compare against. * Added :meth:`~django.db.models.query.QuerySet.earliest` for symmetry with :meth:`~django.db.models.query.QuerySet.latest`. @@ -146,10 +146,10 @@ Minor features * The default widgets for :class:`~django.forms.EmailField`, :class:`~django.forms.URLField`, :class:`~django.forms.IntegerField`, :class:`~django.forms.FloatField` and :class:`~django.forms.DecimalField` use - the new type attributes available in HTML5 (type='email', type='url', - type='number'). Note that due to erratic support of the ``number`` input type - with localized numbers in current browsers, Django only uses it when numeric - fields are not localized. + the new type attributes available in HTML5 (``type='email'``, ``type='url'``, + ``type='number'``). Note that due to erratic support of the ``number`` + input type with localized numbers in current browsers, Django only uses it + when numeric fields are not localized. * The ``number`` argument for :ref:`lazy plural translations <lazy-plural-translations>` can be provided at translation time rather than @@ -185,19 +185,21 @@ Minor features * The jQuery library embedded in the admin has been upgraded to version 1.9.1. * Syndication feeds (:mod:`django.contrib.syndication`) can now pass extra - context through to feed templates using a new `Feed.get_context_data()` - callback. + context through to feed templates using a new + :meth:`Feed.get_context_data() + <django.contrib.syndication.Feed.get_context_data>` callback. * The admin list columns have a ``column-<field_name>`` class in the HTML so the columns header can be styled with CSS, e.g. to set a column width. -* The isolation level can be customized under PostgreSQL. +* The :ref:`isolation level<database-isolation-level>` can be customized under + PostgreSQL. * The :ttag:`blocktrans` template tag now respects :setting:`TEMPLATE_STRING_IF_INVALID` for variables not present in the context, just like other template constructs. -* SimpleLazyObjects will now present more helpful representations in shell +* ``SimpleLazyObject``\s will now present more helpful representations in shell debugging situations. * Generic :class:`~django.contrib.gis.db.models.GeometryField` is now editable @@ -210,7 +212,7 @@ Minor features * The documentation contains a :doc:`deployment checklist </howto/deployment/checklist>`. -* The :djadmin:`diffsettings` comand gained a ``--all`` option. +* The :djadmin:`diffsettings` command gained a ``--all`` option. * ``django.forms.fields.Field.__init__`` now calls ``super()``, allowing field mixins to implement ``__init__()`` methods that will reliably be @@ -234,6 +236,73 @@ Minor features .. _`Pillow`: https://pypi.python.org/pypi/Pillow .. _`PIL`: https://pypi.python.org/pypi/PIL +* :doc:`ModelForm </topics/forms/modelforms/>` accepts a new + Meta option: ``localized_fields``. Fields included in this list will be localized + (by setting ``localize`` on the form field). + +* The ``choices`` argument to model fields now accepts an iterable of iterables + instead of requiring an iterable of lists or tuples. + +* The reason phrase can be customized in HTTP responses using + :attr:`~django.http.HttpResponse.reason_phrase`. + +* When giving the URL of the next page for + :func:`~django.contrib.auth.views.logout`, + :func:`~django.contrib.auth.views.password_reset`, + :func:`~django.contrib.auth.views.password_reset_confirm`, + and :func:`~django.contrib.auth.views.password_change`, you can now pass + URL names and they will be resolved. + +* The :djadmin:`dumpdata` ``manage.py`` command now has a :djadminopt:`--pks` + option which will allow users to specify the primary keys of objects they + want to dump. This option can only be used with one model. + +* Added ``QuerySet`` methods :meth:`~django.db.models.query.QuerySet.first` + and :meth:`~django.db.models.query.QuerySet.last` which are convenience + methods returning the first or last object matching the filters. Returns + ``None`` if there are no objects matching. + +* :class:`~django.views.generic.base.View` and + :class:`~django.views.generic.base.RedirectView` now support HTTP ``PATCH`` + method. + +* :class:`GenericForeignKey <django.contrib.contenttypes.generic.GenericForeignKey>` + now takes an optional + :attr:`~django.contrib.contenttypes.generic.GenericForeignKey.for_concrete_model` + argument, which when set to ``False`` allows the field to reference proxy + models. The default is ``True`` to retain the old behavior. + +* The :class:`~django.middleware.locale.LocaleMiddleware` now stores the active + language in session if it is not present there. This prevents loss of + language settings after session flush, e.g. logout. + +* :exc:`~django.core.exceptions.SuspiciousOperation` has been differentiated + into a number of subclasses, and each will log to a matching named logger + under the ``django.security`` logging hierarchy. Along with this change, + a ``handler400`` mechanism and default view are used whenever + a ``SuspiciousOperation`` reaches the WSGI handler to return an + ``HttpResponseBadRequest``. + +* The :exc:`~django.core.exceptions.DoesNotExist` exception now includes a + message indicating the name of the attribute used for the lookup. + +* The :meth:`~django.db.models.query.QuerySet.get_or_create` method no longer + requires at least one keyword argument. + +* The :class:`~django.test.SimpleTestCase` class includes a new assertion + helper for testing formset errors: + :meth:`~django.test.SimpleTestCase.assertFormsetError`. + +* The list of related fields added to a + :class:`~django.db.models.query.QuerySet` by + :meth:`~django.db.models.query.QuerySet.select_related` can be cleared using + ``select_related(None)``. + +* The :meth:`~django.contrib.admin.InlineModelAdmin.get_extra` and + :meth:`~django.contrib.admin.InlineModelAdmin.get_max_num` methods on + :class:`~django.contrib.admin.InlineModelAdmin` may be overridden to + customize the extra and maximum number of inline forms. + Backwards incompatible changes in 1.6 ===================================== @@ -253,7 +322,7 @@ Behavior changes Database-level autocommit is enabled by default in Django 1.6. While this doesn't change the general spirit of Django's transaction management, there -are a few known backwards-incompatibities, described in the :ref:`transaction +are a few known backwards-incompatibilities, described in the :ref:`transaction management docs <transactions-upgrading-from-1.5>`. You should review your code to determine if you're affected. @@ -264,9 +333,10 @@ The changes in transaction management may result in additional statements to create, release or rollback savepoints. This is more likely to happen with SQLite, since it didn't support savepoints until this release. -If tests using :meth:`~django.test.TestCase.assertNumQueries` fail because of -a higher number of queries than expected, check that the extra queries are -related to savepoints, and adjust the expected number of queries accordingly. +If tests using :meth:`~django.test.TransactionTestCase.assertNumQueries` fail +because of a higher number of queries than expected, check that the extra +queries are related to savepoints, and adjust the expected number of queries +accordingly. Autocommit option for PostgreSQL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -291,21 +361,15 @@ support some types of tests that were supported by the previous runner: your test suite, follow the `recommendations in the Python documentation`_. Django bundles a modified version of the :mod:`doctest` module from the Python -standard library (in ``django.test._doctest``) in order to allow passing in a -custom ``DocTestRunner`` when instantiating a ``DocTestSuite``, and includes -some additional doctest utilities (``django.test.testcases.DocTestRunner`` -turns on the ``ELLIPSIS`` option by default, and -``django.test.testcases.OutputChecker`` provides better matching of XML, JSON, -and numeric data types). - -These utilities are deprecated and will be removed in Django 1.8; doctest -suites should be updated to work with the standard library's doctest module (or -converted to unittest-compatible tests). +standard library (in ``django.test._doctest``) and includes some additional +doctest utilities. These utilities are deprecated and will be removed in Django +1.8; doctest suites should be updated to work with the standard library's +doctest module (or converted to unittest-compatible tests). If you wish to delay updates to your test suite, you can set your :setting:`TEST_RUNNER` setting to ``django.test.simple.DjangoTestSuiteRunner`` -to fully restore the old test behavior. ``DjangoTestSuiteRunner`` is -deprecated but will not be removed from Django until version 1.8. +to fully restore the old test behavior. ``DjangoTestSuiteRunner`` is deprecated +but will not be removed from Django until version 1.8. .. _recommendations in the Python documentation: http://docs.python.org/2/library/doctest.html#unittest-api @@ -395,10 +459,9 @@ they are located after a ``{#`` / ``#}``-type comment on the same line. E.g.: Location of translator comments ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Validation of the placement of :ref:`translator-comments-in-templates` -specified using ``{#`` / ``#}`` is now stricter. All translator comments not -located at the end of their respective lines in a template are ignored and a -warning is generated by :djadmin:`makemessages` when it finds them. E.g.: +:ref:`translator-comments-in-templates` specified using ``{#`` / ``#}`` need to +be at the end of a line. If they are not, the comments are ignored and +:djadmin:`makemessages` will generate a warning. For example: .. code-block:: html+django @@ -439,7 +502,7 @@ For Oracle, execute this query: ALTER TABLE DJANGO_COMMENTS MODIFY (ip_address VARCHAR2(39)); -If you do not apply this change, the behaviour is unchanged: on MySQL, IPv6 +If you do not apply this change, the behavior is unchanged: on MySQL, IPv6 addresses are silently truncated; on Oracle, an exception is generated. No database change is needed for SQLite or PostgreSQL databases. @@ -461,6 +524,63 @@ parameters. For example:: ``SQLite`` users need to check and update such queries. +.. _m2m-help_text: + +Help text of model form fields for ManyToManyField fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HTML rendering of model form fields corresponding to +:class:`~django.db.models.ManyToManyField` ORM model fields used to get the +hard-coded sentence + + *Hold down "Control", or "Command" on a Mac, to select more than one.* + +(or its translation to the active locale) imposed as the help legend shown along +them if neither :attr:`model <django.db.models.Field.help_text>` nor :attr:`form +<django.forms.Field.help_text>` ``help_text`` attribute was specified by the +user (or appended to, if ``help_text`` was provided.) + +This happened always, possibly even with form fields implementing user +interactions that don't involve a keyboard and/or a mouse and was handled at the +model field layer. + +Starting with Django 1.6 this doesn't happen anymore. + +The change can affect you in a backward incompatible way if you employ custom +model form fields and/or widgets for ``ManyToManyField`` model fields whose UIs +do rely on the automatic provision of the mentioned hard-coded sentence. These +form field implementations need to adapt to the new scenario by providing their +own handling of the ``help_text`` attribute. + +Applications that use Django :doc:`model form </topics/forms/modelforms>` +facilities together with Django built-in form :doc:`fields </ref/forms/fields>` +and :doc:`widgets </ref/forms/widgets>` aren't affected but need to be aware of +what's described in :ref:`m2m-help_text-deprecation` below. + +This is because, as an ad-hoc temporary backward-compatibility provision, the +described non-standard behavior has been preserved but moved to the model form +field layer and occurs only when the associated widget is +:class:`~django.forms.SelectMultiple` or selected subclasses. + +QuerySet iteration +~~~~~~~~~~~~~~~~~~ + +The ``QuerySet`` iteration was changed to immediately convert all fetched +rows to ``Model`` objects. In Django 1.5 and earlier the fetched rows were +converted to ``Model`` objects in chunks of 100. + +Existing code will work, but the amount of rows converted to objects +might change in certain use cases. Such usages include partially looping +over a queryset or any usage which ends up doing ``__bool__`` or +``__contains__``. + +Notably most database backends did fetch all the rows in one go already in +1.5. + +It is still possible to convert the fetched rows to ``Model`` objects +lazily by using the :meth:`~django.db.models.query.QuerySet.iterator()` +method. + Miscellaneous ~~~~~~~~~~~~~ @@ -481,6 +601,39 @@ Miscellaneous changes in 1.6 particularly affect :class:`~django.forms.DecimalField` and :class:`~django.forms.ModelMultipleChoiceField`. +* There have been changes in the way timeouts are handled in cache backends. + Explicitly passing in ``timeout=None`` no longer results in using the + default timeout. It will now set a non-expiring timeout. Passing 0 into the + memcache backend no longer uses the default timeout, and now will + set-and-expire-immediately the value. + +* The ``django.contrib.flatpages`` app used to set custom HTTP headers for + debugging purposes. This functionality was not documented and made caching + ineffective so it has been removed, along with its generic implementation, + previously available in ``django.core.xheaders``. + +* The ``XViewMiddleware`` has been moved from ``django.middleware.doc`` to + ``django.contrib.admindocs.middleware`` because it is an implementation + detail of admindocs, proven not to be reusable in general. + +* :class:`~django.db.models.GenericIPAddressField` will now only allow + ``blank`` values if ``null`` values are also allowed. Creating a + ``GenericIPAddressField`` where ``blank`` is allowed but ``null`` is not + will trigger a model validation error because ``blank`` values are always + stored as ``null``. Previously, storing a ``blank`` value in a field which + did not allow ``null`` would cause a database exception at runtime. + +* If a :class:`~django.core.urlresolvers.NoReverseMatch` exception is raised + from a method when rendering a template, it is not silenced. For example, + ``{{ obj.view_href }}`` will cause template rendering to fail if + ``view_href()`` raises ``NoReverseMatch``. There is no change to the + ``{% url %}`` tag, it causes template rendering to fail like always when + ``NoReverseMatch`` is risen. + +* :meth:`django.test.client.Client.logout` now calls + :meth:`django.contrib.auth.logout` which will send the + :func:`~django.contrib.auth.signals.user_logged_out` signal. + Features deprecated in 1.6 ========================== @@ -551,6 +704,23 @@ If necessary, you can temporarily disable auto-escaping with :func:`~django.utils.safestring.mark_safe` or :ttag:`{% autoescape off %} <autoescape>`. +``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``CacheMiddleware`` used to provide a way to cache requests only if they +weren't made by a logged-in user. This mechanism was largely ineffective +because the middleware correctly takes into account the ``Vary: Cookie`` HTTP +header, and this header is being set on a variety of occasions, such as: + +* accessing the session, or +* using CSRF protection, which is turned on by default, or +* using a client-side library which sets cookies, like `Google Analytics`__. + +This makes the cache effectively work on a per-session basis regardless of the +``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting. + +__ http://www.google.com/analytics/ + ``SEND_BROKEN_LINK_EMAILS`` setting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -575,7 +745,7 @@ from your settings. If you defined your own form widgets and defined the ``_has_changed`` method on a widget, you should now define this method on the form field itself. -``module_name`` model meta attribute +``module_name`` model _meta attribute ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``Model._meta.module_name`` was renamed to ``model_name``. Despite being a @@ -617,7 +787,7 @@ particular with boolean fields, it is possible for this problem to be completely invisible. This is a form of `Mass assignment vulnerability <http://en.wikipedia.org/wiki/Mass_assignment_vulnerability>`_. -For this reason, this behaviour is deprecated, and using the ``Meta.exclude`` +For this reason, this behavior is deprecated, and using the ``Meta.exclude`` option is strongly discouraged. Instead, all fields that are intended for inclusion in the form should be listed explicitly in the ``fields`` attribute. @@ -636,7 +806,7 @@ is another option. The admin has its own methods for defining fields redundant. Instead, simply omit the ``Meta`` inner class of the ``ModelForm``, or omit the ``Meta.model`` attribute. Since the ``ModelAdmin`` subclass knows which model it is for, it can add the necessary attributes to derive a -functioning ``ModelForm``. This behaviour also works for earlier Django +functioning ``ModelForm``. This behavior also works for earlier Django versions. ``UpdateView`` and ``CreateView`` without explicit fields @@ -655,3 +825,16 @@ you can set set the ``form_class`` attribute to a ``ModelForm`` that explicitly defines the fields to be used. Defining an ``UpdateView`` or ``CreateView`` subclass to be used with a model but without an explicit list of fields is deprecated. + +.. _m2m-help_text-deprecation: + +Munging of help text of model form fields for ``ManyToManyField`` fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All special handling of the ``help_text`` attribute of ``ManyToManyField`` model +fields performed by standard model or model form fields as described in +:ref:`m2m-help_text` above is deprecated and will be removed in Django 1.8. + +Help text of these fields will need to be handled either by applications, custom +form fields or widgets, just like happens with the rest of the model field +types. diff --git a/docs/releases/index.txt b/docs/releases/index.txt index c5afd8c719..85b3d211a8 100644 --- a/docs/releases/index.txt +++ b/docs/releases/index.txt @@ -6,10 +6,11 @@ Release notes for the official Django releases. Each release note will tell you what's new in each version, and will also describe any backwards-incompatible changes made in that version. -For those upgrading to a new version of Django, you will need to check -all the backwards-incompatible changes and deprecated features for -each 'final' release from the one after your current Django version, -up to and including the new version. +For those :doc:`upgrading to a new version of Django</howto/upgrade-version>`, +you will need to check all the backwards-incompatible changes and +:doc:`deprecated features</internals/deprecation>` for each 'final' release +from the one after your current Django version, up to and including the new +version. Final releases ============== diff --git a/docs/topics/auth/customizing.txt b/docs/topics/auth/customizing.txt index 56f3e60350..bc021b14ad 100644 --- a/docs/topics/auth/customizing.txt +++ b/docs/topics/auth/customizing.txt @@ -939,7 +939,7 @@ authentication app:: raise ValueError('Users must have an email address') user = self.model( - email=MyUserManager.normalize_email(email), + email=self.normalize_email(email), date_of_birth=date_of_birth, ) @@ -1075,7 +1075,6 @@ code would be required in the app's ``admin.py`` file:: (None, {'fields': ('email', 'password')}), ('Personal info', {'fields': ('date_of_birth',)}), ('Permissions', {'fields': ('is_admin',)}), - ('Important dates', {'fields': ('last_login',)}), ) add_fieldsets = ( (None, { @@ -1092,3 +1091,8 @@ code would be required in the app's ``admin.py`` file:: # ... and, since we're not using Django's builtin permissions, # unregister the Group model from admin. admin.site.unregister(Group) + +Finally, specify the custom model as the default user model for your project +using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``:: + + AUTH_USER_MODEL = 'customauth.MyUser' diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt index 6b6d57511a..2352770bad 100644 --- a/docs/topics/cache.txt +++ b/docs/topics/cache.txt @@ -443,15 +443,9 @@ Then, add the following required settings to your Django settings file: The cache middleware caches GET and HEAD responses with status 200, where the request and response headers allow. Responses to requests for the same URL with different query parameters are considered to be unique pages and are cached separately. -Optionally, if the :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY` -setting is ``True``, only anonymous requests (i.e., not those made by a -logged-in user) will be cached. This is a simple and effective way of disabling -caching for any user-specific pages (including Django's admin interface). Note -that if you use :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY`, you should make -sure you've activated ``AuthenticationMiddleware``. The cache middleware -expects that a HEAD request is answered with the same response headers as -the corresponding GET request; in which case it can return a cached GET -response for HEAD request. +The cache middleware expects that a HEAD request is answered with the same +response headers as the corresponding GET request; in which case it can return +a cached GET response for HEAD request. Additionally, the cache middleware automatically sets a few headers in each :class:`~django.http.HttpResponse`: @@ -707,10 +701,15 @@ The basic interface is ``set(key, value, timeout)`` and ``get(key)``:: >>> cache.get('my_key') 'hello, world!' -The ``timeout`` argument is optional and defaults to the ``timeout`` -argument of the appropriate backend in the :setting:`CACHES` setting -(explained above). It's the number of seconds the value should be stored -in the cache. +The ``timeout`` argument is optional and defaults to the ``timeout`` argument +of the appropriate backend in the :setting:`CACHES` setting (explained above). +It's the number of seconds the value should be stored in the cache. Passing in +``None`` for ``timeout`` will cache the value forever. + +.. versionchanged:: 1.6 + + Previously, passing ``None`` explicitly would use the default timeout + value. If the object doesn't exist in the cache, ``cache.get()`` returns ``None``:: @@ -998,8 +997,8 @@ produces different content based on some difference in request headers -- such as a cookie, or a language, or a user-agent -- you'll need to use the ``Vary`` header to tell caching mechanisms that the page output depends on those things. -To do this in Django, use the convenient ``vary_on_headers`` view decorator, -like so:: +To do this in Django, use the convenient +:func:`django.views.decorators.vary.vary_on_headers` view decorator, like so:: from django.views.decorators.vary import vary_on_headers @@ -1028,8 +1027,9 @@ the user-agent ``Mozilla`` and the cookie value ``foo=bar`` will be considered different from a request with the user-agent ``Mozilla`` and the cookie value ``foo=ham``. -Because varying on cookie is so common, there's a ``vary_on_cookie`` -decorator. These two views are equivalent:: +Because varying on cookie is so common, there's a +:func:`django.views.decorators.vary.vary_on_cookie` decorator. These two views +are equivalent:: @vary_on_cookie def my_view(request): @@ -1042,7 +1042,7 @@ decorator. These two views are equivalent:: The headers you pass to ``vary_on_headers`` are not case sensitive; ``"User-Agent"`` is the same thing as ``"user-agent"``. -You can also use a helper function, ``django.utils.cache.patch_vary_headers``, +You can also use a helper function, :func:`django.utils.cache.patch_vary_headers`, directly. This function sets, or adds to, the ``Vary header``. For example:: from django.utils.cache import patch_vary_headers @@ -1091,8 +1091,9 @@ exclusive. The decorator ensures that the "public" directive is removed if "private" should be set (and vice versa). An example use of the two directives would be a blog site that offers both private and public entries. Public entries may be cached on any shared cache. The following code uses -``patch_cache_control``, the manual way to modify the cache control header -(it is internally called by the ``cache_control`` decorator):: +:func:`django.utils.cache.patch_cache_control`, the manual way to modify the +cache control header (it is internally called by the ``cache_control`` +decorator):: from django.views.decorators.cache import patch_cache_control from django.views.decorators.vary import vary_on_cookie diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt index 64b998770f..7ffa471e79 100644 --- a/docs/topics/class-based-views/generic-display.txt +++ b/docs/topics/class-based-views/generic-display.txt @@ -248,7 +248,7 @@ specify the objects that the view will operate upon -- you can also specify the list of objects using the ``queryset`` argument:: from django.views.generic import DetailView - from books.models import Publisher, Book + from books.models import Publisher class PublisherDetail(DetailView): @@ -326,6 +326,7 @@ various useful things are stored on ``self``; as well as the request Here, we have a URLconf with a single captured group:: # urls.py + from django.conf.urls import patterns from books.views import PublisherBookList urlpatterns = patterns('', @@ -375,6 +376,7 @@ Imagine we had a ``last_accessed`` field on our ``Author`` object that we were using to keep track of the last time anybody looked at that author:: # models.py + from django.db import models class Author(models.Model): salutation = models.CharField(max_length=10) @@ -390,6 +392,7 @@ updated. First, we'd need to add an author detail bit in the URLconf to point to a custom view:: + from django.conf.urls import patterns, url from books.views import AuthorDetailView urlpatterns = patterns('', @@ -401,7 +404,6 @@ Then we'd write our new view -- ``get_object`` is the method that retrieves the object -- so we simply override it and wrap the call:: from django.views.generic import DetailView - from django.shortcuts import get_object_or_404 from django.utils import timezone from books.models import Author diff --git a/docs/topics/class-based-views/generic-editing.txt b/docs/topics/class-based-views/generic-editing.txt index 86c5280159..7c4e02cc4e 100644 --- a/docs/topics/class-based-views/generic-editing.txt +++ b/docs/topics/class-based-views/generic-editing.txt @@ -222,6 +222,7 @@ works for AJAX requests as well as 'normal' form POSTs:: from django.http import HttpResponse from django.views.generic.edit import CreateView + from myapp.models import Author class AjaxableResponseMixin(object): """ diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt index 9550d2fb86..980e571c85 100644 --- a/docs/topics/class-based-views/mixins.txt +++ b/docs/topics/class-based-views/mixins.txt @@ -258,6 +258,7 @@ mixin. We can hook this into our URLs easily enough:: # urls.py + from django.conf.urls import patterns, url from books.views import RecordInterest urlpatterns = patterns('', @@ -440,6 +441,7 @@ Our new ``AuthorDetail`` looks like this:: from django.core.urlresolvers import reverse from django.views.generic import DetailView from django.views.generic.edit import FormMixin + from books.models import Author class AuthorInterestForm(forms.Form): message = forms.CharField() @@ -546,6 +548,8 @@ template as ``AuthorDisplay`` is using on ``GET``. .. code-block:: python + from django.core.urlresolvers import reverse + from django.http import HttpResponseForbidden from django.views.generic import FormView from django.views.generic.detail import SingleObjectMixin @@ -657,6 +661,8 @@ own version of :class:`~django.views.generic.detail.DetailView` by mixing :class:`~django.views.generic.detail.DetailView` before template rendering behavior has been mixed in):: + from django.views.generic.detail import BaseDetailView + class JSONDetailView(JSONResponseMixin, BaseDetailView): pass @@ -675,6 +681,8 @@ and override the implementation of to defer to the appropriate subclass depending on the type of response that the user requested:: + from django.views.generic.detail import SingleObjectTemplateResponseMixin + class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView): def render_to_response(self, context): # Look for a 'format=json' GET argument diff --git a/docs/topics/db/aggregation.txt b/docs/topics/db/aggregation.txt index 125cd0bdee..1024d6b0c2 100644 --- a/docs/topics/db/aggregation.txt +++ b/docs/topics/db/aggregation.txt @@ -18,27 +18,29 @@ used to track the inventory for a series of online bookstores: .. code-block:: python + from django.db import models + class Author(models.Model): - name = models.CharField(max_length=100) - age = models.IntegerField() + name = models.CharField(max_length=100) + age = models.IntegerField() class Publisher(models.Model): - name = models.CharField(max_length=300) - num_awards = models.IntegerField() + name = models.CharField(max_length=300) + num_awards = models.IntegerField() class Book(models.Model): - name = models.CharField(max_length=300) - pages = models.IntegerField() - price = models.DecimalField(max_digits=10, decimal_places=2) - rating = models.FloatField() - authors = models.ManyToManyField(Author) - publisher = models.ForeignKey(Publisher) - pubdate = models.DateField() + name = models.CharField(max_length=300) + pages = models.IntegerField() + price = models.DecimalField(max_digits=10, decimal_places=2) + rating = models.FloatField() + authors = models.ManyToManyField(Author) + publisher = models.ForeignKey(Publisher) + pubdate = models.DateField() class Store(models.Model): - name = models.CharField(max_length=300) - books = models.ManyToManyField(Book) - registered_users = models.PositiveIntegerField() + name = models.CharField(max_length=300) + books = models.ManyToManyField(Book) + registered_users = models.PositiveIntegerField() Cheat sheet =========== @@ -123,7 +125,7 @@ If you want to generate more than one aggregate, you just add another argument to the ``aggregate()`` clause. So, if we also wanted to know the maximum and minimum price of all books, we would issue the query:: - >>> from django.db.models import Avg, Max, Min, Count + >>> from django.db.models import Avg, Max, Min >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')} @@ -148,6 +150,7 @@ the number of authors: .. code-block:: python # Build an annotated queryset + >>> from django.db.models import Count >>> q = Book.objects.annotate(Count('authors')) # Interrogate the first object in the queryset >>> q[0] @@ -192,6 +195,7 @@ and aggregate the related value. For example, to find the price range of books offered in each store, you could use the annotation:: + >>> from django.db.models import Max, Min >>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price')) This tells Django to retrieve the ``Store`` model, join (through the @@ -222,7 +226,7 @@ For example, we can ask for all publishers, annotated with their respective total book stock counters (note how we use ``'book'`` to specify the ``Publisher`` -> ``Book`` reverse foreign key hop):: - >>> from django.db.models import Count, Min, Sum, Max, Avg + >>> from django.db.models import Count, Min, Sum, Avg >>> Publisher.objects.annotate(Count('book')) (Every ``Publisher`` in the resulting ``QuerySet`` will have an extra attribute @@ -269,6 +273,7 @@ constraining the objects for which an annotation is calculated. For example, you can generate an annotated list of all books that have a title starting with "Django" using the query:: + >>> from django.db.models import Count, Avg >>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors')) When used with an ``aggregate()`` clause, a filter has the effect of @@ -407,6 +412,8 @@ particularly, when counting things. By way of example, suppose you have a model like this:: + from django.db import models + class Item(models.Model): name = models.CharField(max_length=10) data = models.IntegerField() @@ -457,5 +464,6 @@ For example, if you wanted to calculate the average number of authors per book you first annotate the set of books with the author count, then aggregate that author count, referencing the annotation field:: + >>> from django.db.models import Count, Avg >>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors')) {'num_authors__avg': 1.66} diff --git a/docs/topics/db/managers.txt b/docs/topics/db/managers.txt index 2a0f7e4ce0..b940b09d33 100644 --- a/docs/topics/db/managers.txt +++ b/docs/topics/db/managers.txt @@ -62,6 +62,8 @@ For example, this custom ``Manager`` offers a method ``with_counts()``, which returns a list of all ``OpinionPoll`` objects, each with an extra ``num_responses`` attribute that is the result of an aggregate query:: + from django.db import models + class PollManager(models.Manager): def with_counts(self): from django.db import connection @@ -101,6 +103,8 @@ Modifying initial Manager QuerySets A ``Manager``'s base ``QuerySet`` returns all objects in the system. For example, using this model:: + from django.db import models + class Book(models.Model): title = models.CharField(max_length=100) author = models.CharField(max_length=50) @@ -236,7 +240,7 @@ class, but still customize the default manager. For example, suppose you have this base class:: class AbstractBase(models.Model): - ... + # ... objects = CustomManager() class Meta: @@ -246,14 +250,15 @@ If you use this directly in a subclass, ``objects`` will be the default manager if you declare no managers in the base class:: class ChildA(AbstractBase): - ... + # ... # This class has CustomManager as the default manager. + pass If you want to inherit from ``AbstractBase``, but provide a different default manager, you can provide the default manager on the child class:: class ChildB(AbstractBase): - ... + # ... # An explicit default manager. default_manager = OtherManager() @@ -274,9 +279,10 @@ it into the inheritance hierarchy *after* the defaults:: abstract = True class ChildC(AbstractBase, ExtraManager): - ... + # ... # Default manager is CustomManager, but OtherManager is # also available via the "extra_manager" attribute. + pass Note that while you can *define* a custom manager on the abstract model, you can't *invoke* any methods using the abstract model. That is:: @@ -349,8 +355,7 @@ the manager class:: class MyManager(models.Manager): use_for_related_fields = True - - ... + # ... If this attribute is set on the *default* manager for a model (only the default manager is considered in these situations), Django will use that class @@ -396,7 +401,8 @@ it, whereas the following will not work:: # BAD: Incorrect code class MyManager(models.Manager): - ... + # ... + pass # Sets the attribute on an instance of MyManager. Django will # ignore this setting. @@ -404,7 +410,7 @@ it, whereas the following will not work:: mgr.use_for_related_fields = True class MyModel(models.Model): - ... + # ... objects = mgr # End of incorrect code. diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index dd7714052d..c0ba53ddd7 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -90,6 +90,8 @@ attributes. Be careful not to choose field names that conflict with the Example:: + from django.db import models + class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @@ -180,7 +182,7 @@ ones: ('L', 'Large'), ) name = models.CharField(max_length=60) - shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES) + shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) :: @@ -290,8 +292,11 @@ For example, if a ``Car`` model has a ``Manufacturer`` -- that is, a ``Manufacturer`` makes multiple cars but each ``Car`` only has one ``Manufacturer`` -- use the following definitions:: + from django.db import models + class Manufacturer(models.Model): # ... + pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer) @@ -340,8 +345,11 @@ For example, if a ``Pizza`` has multiple ``Topping`` objects -- that is, a ``Topping`` can be on multiple pizzas and each ``Pizza`` has multiple toppings -- here's how you'd represent that:: + from django.db import models + class Topping(models.Model): # ... + pass class Pizza(models.Model): # ... @@ -403,6 +411,8 @@ intermediate model. The intermediate model is associated with the that will act as an intermediary. For our musician example, the code would look something like this:: + from django.db import models + class Person(models.Model): name = models.CharField(max_length=128) @@ -583,6 +593,7 @@ It's perfectly OK to relate a model to one from another app. To do this, import the related model at the top of the file where your model is defined. Then, just refer to the other model class wherever needed. For example:: + from django.db import models from geography.models import ZipCode class Restaurant(models.Model): @@ -630,6 +641,8 @@ Meta options Give your model metadata by using an inner ``class Meta``, like so:: + from django.db import models + class Ox(models.Model): horn_length = models.IntegerField() @@ -660,6 +673,8 @@ model. For example, this model has a few custom methods:: + from django.db import models + class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @@ -729,6 +744,8 @@ A classic use-case for overriding the built-in methods is if you want something to happen whenever you save an object. For example (see :meth:`~Model.save` for documentation of the parameters it accepts):: + from django.db import models + class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() @@ -740,6 +757,8 @@ to happen whenever you save an object. For example (see You can also prevent saving:: + from django.db import models + class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() @@ -826,6 +845,8 @@ the child (and Django will raise an exception). An example:: + from django.db import models + class CommonInfo(models.Model): name = models.CharField(max_length=100) age = models.PositiveIntegerField() @@ -854,14 +875,16 @@ attribute. If a child class does not declare its own :ref:`Meta <meta-options>` class, it will inherit the parent's :ref:`Meta <meta-options>`. If the child wants to extend the parent's :ref:`Meta <meta-options>` class, it can subclass it. For example:: + from django.db import models + class CommonInfo(models.Model): - ... + # ... class Meta: abstract = True ordering = ['name'] class Student(CommonInfo): - ... + # ... class Meta(CommonInfo.Meta): db_table = 'student_info' @@ -901,6 +924,8 @@ abstract base class (only), part of the name should contain For example, given an app ``common/models.py``:: + from django.db import models + class Base(models.Model): m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") @@ -949,6 +974,8 @@ relationship introduces links between the child model and each of its parents (via an automatically-created :class:`~django.db.models.OneToOneField`). For example:: + from django.db import models + class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) @@ -998,7 +1025,7 @@ If the parent has an ordering and you don't want the child to have any natural ordering, you can explicitly disable it:: class ChildModel(ParentModel): - ... + # ... class Meta: # Remove parent's ordering effect ordering = [] @@ -1061,15 +1088,21 @@ Proxy models are declared like normal models. You tell Django that it's a proxy model by setting the :attr:`~django.db.models.Options.proxy` attribute of the ``Meta`` class to ``True``. -For example, suppose you want to add a method to the ``Person`` model described -above. You can do it like this:: +For example, suppose you want to add a method to the ``Person`` model. You can do it like this:: + + from django.db import models + + class Person(models.Model): + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class MyPerson(Person): class Meta: proxy = True def do_something(self): - ... + # ... + pass The ``MyPerson`` class operates on the same database table as its parent ``Person`` class. In particular, any new instances of ``Person`` will also be @@ -1125,8 +1158,11 @@ classes will still be available. Continuing our example from above, you could change the default manager used when you query the ``Person`` model like this:: + from django.db import models + class NewManager(models.Manager): - ... + # ... + pass class MyPerson(Person): objects = NewManager() diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 2553eac27a..bdbdd3fa2a 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -17,6 +17,8 @@ models, which comprise a Weblog application: .. code-block:: python + from django.db import models + class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() @@ -100,7 +102,8 @@ Saving ``ForeignKey`` and ``ManyToManyField`` fields Updating a :class:`~django.db.models.ForeignKey` field works exactly the same way as saving a normal field -- simply assign an object of the right type to the field in question. This example updates the ``blog`` attribute of an -``Entry`` instance ``entry``:: +``Entry`` instance ``entry``, assuming appropriate instances of ``Entry`` and +``Blog`` are already saved to the database (so we can retrieve them below):: >>> from blog.models import Entry >>> entry = Entry.objects.get(pk=1) @@ -711,9 +714,9 @@ for you transparently. Caching and QuerySets --------------------- -Each :class:`~django.db.models.query.QuerySet` contains a cache, to minimize -database access. It's important to understand how it works, in order to write -the most efficient code. +Each :class:`~django.db.models.query.QuerySet` contains a cache to minimize +database access. Understanding how it works will allow you to write the most +efficient code. In a newly created :class:`~django.db.models.query.QuerySet`, the cache is empty. The first time a :class:`~django.db.models.query.QuerySet` is evaluated @@ -744,6 +747,43 @@ To avoid this problem, simply save the >>> print([p.headline for p in queryset]) # Evaluate the query set. >>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation. +When querysets are not cached +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Querysets do not always cache their results. When evaluating only *part* of +the queryset, the cache is checked, but if it is not populated then the items +returned by the subsequent query are not cached. Specifically, this means that +:ref:`limiting the queryset <limiting-querysets>` using an array slice or an +index will not populate the cache. + +For example, repeatedly getting a certain index in a queryset object will query +the database each time:: + + >>> queryset = Entry.objects.all() + >>> print queryset[5] # Queries the database + >>> print queryset[5] # Queries the database again + +However, if the entire queryset has already been evaluated, the cache will be +checked instead:: + + >>> queryset = Entry.objects.all() + >>> [entry for entry in queryset] # Queries the database + >>> print queryset[5] # Uses cache + >>> print queryset[5] # Uses cache + +Here are some examples of other actions that will result in the entire queryset +being evaluated and therefore populate the cache:: + + >>> [entry for entry in queryset] + >>> bool(queryset) + >>> entry in queryset + >>> list(queryset) + +.. note:: + + Simply printing the queryset will not populate the cache. This is because + the call to ``__repr__()`` only returns a slice of the entire queryset. + .. _complex-lookups-with-q: Complex lookups with Q objects diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt index 78786996cd..e9a626f56b 100644 --- a/docs/topics/db/transactions.txt +++ b/docs/topics/db/transactions.txt @@ -45,14 +45,6 @@ You may perfom partial commits and rollbacks in your view code, typically with the :func:`atomic` context manager. However, at the end of the view, either all the changes will be committed, or none of them. -To disable this behavior for a specific view, you must set the -``transactions_per_request`` attribute of the view function itself to -``False``, like this:: - - def my_view(request): - do_stuff() - my_view.transactions_per_request = False - .. warning:: While the simplicity of this transaction model is appealing, it also makes it @@ -78,6 +70,26 @@ Note that only the execution of your view is enclosed in the transactions. Middleware runs outside of the transaction, and so does the rendering of template responses. +When :setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>` is enabled, it's +still possible to prevent views from running in a transaction. + +.. function:: non_atomic_requests(using=None) + + This decorator will negate the effect of :setting:`ATOMIC_REQUESTS + <DATABASE-ATOMIC_REQUESTS>` for a given view:: + + from django.db import transaction + + @transaction.non_atomic_requests + def my_view(request): + do_stuff() + + @transaction.non_atomic_requests(using='other') + def my_other_view(request): + do_stuff_on_the_other_database() + + It only works if it's applied to the view itself. + .. versionchanged:: 1.6 Django used to provide this feature via ``TransactionMiddleware``, which is @@ -519,8 +531,8 @@ Transaction states ------------------ The three functions described above relied on a concept called "transaction -states". This mechanisme was deprecated in Django 1.6, but it's still -available until Django 1.8. +states". This mechanism was deprecated in Django 1.6, but it's still available +until Django 1.8. At any time, each database connection is in one of these two states: @@ -552,25 +564,16 @@ API changes Transaction middleware ~~~~~~~~~~~~~~~~~~~~~~ -In Django 1.6, ``TransactionMiddleware`` is deprecated and replaced +In Django 1.6, ``TransactionMiddleware`` is deprecated and replaced by :setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>`. While the general -behavior is the same, there are a few differences. - -With the transaction middleware, it was still possible to switch to autocommit -or to commit explicitly in a view. Since :func:`atomic` guarantees atomicity, -this isn't allowed any longer. +behavior is the same, there are two differences. -To avoid wrapping a particular view in a transaction, instead of:: - - @transaction.autocommit - def my_view(request): - do_stuff() - -you must now use this pattern:: - - def my_view(request): - do_stuff() - my_view.transactions_per_request = False +With the previous API, it was possible to switch to autocommit or to commit +explicitly anywhere inside a view. Since :setting:`ATOMIC_REQUESTS +<DATABASE-ATOMIC_REQUESTS>` relies on :func:`atomic` which enforces atomicity, +this isn't allowed any longer. However, at the toplevel, it's still possible +to avoid wrapping an entire view in a transaction. To achieve this, decorate +the view with :func:`non_atomic_requests` instead of :func:`autocommit`. The transaction middleware applied not only to view functions, but also to middleware modules that came after it. For instance, if you used the session @@ -624,6 +627,9 @@ you should now use:: finally: transaction.set_autocommit(False) +Unless you're implementing a transaction management framework, you shouldn't +ever need to do this. + Disabling transaction management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -653,7 +659,7 @@ Sequences of custom SQL queries If you're executing several :ref:`custom SQL queries <executing-custom-sql>` in a row, each one now runs in its own transaction, instead of sharing the same "automatic transaction". If you need to enforce atomicity, you must wrap -the sequence of queries in :func:`commit_on_success`. +the sequence of queries in :func:`atomic`. To check for this problem, look for calls to ``cursor.execute()``. They're usually followed by a call to ``transaction.commit_unless_managed()``, which diff --git a/docs/topics/files.txt b/docs/topics/files.txt index fb3cdd4af9..492e6a20b5 100644 --- a/docs/topics/files.txt +++ b/docs/topics/files.txt @@ -27,6 +27,8 @@ to deal with that file. Consider the following model, using an :class:`~django.db.models.ImageField` to store a photo:: + from django.db import models + class Car(models.Model): name = models.CharField(max_length=255) price = models.DecimalField(max_digits=5, decimal_places=2) diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt index 9d77cd5274..8745e9761d 100644 --- a/docs/topics/forms/formsets.txt +++ b/docs/topics/forms/formsets.txt @@ -56,6 +56,9 @@ telling the formset how many additional forms to show in addition to the number of forms it generates from the initial data. Lets take a look at an example:: + >>> import datetime + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) >>> formset = ArticleFormSet(initial=[ ... {'title': u'Django is now open source', @@ -88,6 +91,8 @@ The ``max_num`` parameter to :func:`~django.forms.formsets.formset_factory` gives you the ability to limit the maximum number of empty forms the formset will display:: + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1) >>> formset = ArticleFormSet() >>> for form in formset: @@ -124,6 +129,8 @@ Validation with a formset is almost identical to a regular ``Form``. There is an ``is_valid`` method on the formset to provide a convenient way to validate all forms in the formset:: + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm) >>> data = { ... 'form-TOTAL_FORMS': u'1', @@ -230,6 +237,8 @@ A formset has a ``clean`` method similar to the one on a ``Form`` class. This is where you define your own validation that works at the formset level:: >>> from django.forms.formsets import BaseFormSet + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> class BaseArticleFormSet(BaseFormSet): ... def clean(self): @@ -274,8 +283,11 @@ Validating the number of forms in a formset If ``validate_max=True`` is passed to :func:`~django.forms.formsets.formset_factory`, validation will also check -that the number of forms in the data set is less than or equal to ``max_num``. +that the number of forms in the data set, minus those marked for +deletion, is less than or equal to ``max_num``. + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm, max_num=1, validate_max=True) >>> data = { ... 'form-TOTAL_FORMS': u'2', @@ -329,6 +341,8 @@ Default: ``False`` Lets you create a formset with the ability to order:: + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True) >>> formset = ArticleFormSet(initial=[ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, @@ -385,6 +399,8 @@ Default: ``False`` Lets you create a formset with the ability to delete:: + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True) >>> formset = ArticleFormSet(initial=[ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, @@ -437,6 +453,9 @@ accomplished. The formset base class provides an ``add_fields`` method. You can simply override this method to add your own fields or even redefine the default fields/attributes of the order and deletion fields:: + >>> from django.forms.formsets import BaseFormSet + >>> from django.forms.formsets import formset_factory + >>> from myapp.forms import ArticleForm >>> class BaseArticleFormSet(BaseFormSet): ... def add_fields(self, form, index): ... super(BaseArticleFormSet, self).add_fields(form, index) @@ -459,6 +478,10 @@ management form inside the template. Let's look at a sample view: .. code-block:: python + from django.forms.formsets import formset_factory + from django.shortcuts import render_to_response + from myapp.forms import ArticleForm + def manage_articles(request): ArticleFormSet = formset_factory(ArticleForm) if request.method == 'POST': @@ -534,6 +557,10 @@ a look at how this might be accomplished: .. code-block:: python + from django.forms.formsets import formset_factory + from django.shortcuts import render_to_response + from myapp.forms import ArticleForm, BookForm + def manage_articles(request): ArticleFormSet = formset_factory(ArticleForm) BookFormSet = formset_factory(BookForm) diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt index c0d63bb8cf..b014e97119 100644 --- a/docs/topics/forms/media.txt +++ b/docs/topics/forms/media.txt @@ -49,6 +49,8 @@ define the media requirements. Here's a simple example:: + from django import froms + class CalendarWidget(forms.TextInput): class Media: css = { @@ -211,6 +213,7 @@ to using :setting:`MEDIA_URL`. For example, if the :setting:`MEDIA_URL` for your site was ``'http://uploads.example.com/'`` and :setting:`STATIC_URL` was ``None``:: + >>> from django import forms >>> class CalendarWidget(forms.TextInput): ... class Media: ... css = { @@ -267,6 +270,7 @@ Combining media objects Media objects can also be added together. When two media objects are added, the resulting Media object contains the union of the media from both files:: + >>> from django import forms >>> class CalendarWidget(forms.TextInput): ... class Media: ... css = { @@ -298,6 +302,7 @@ Regardless of whether you define a media declaration, *all* Form objects have a media property. The default value for this property is the result of adding the media definitions for all widgets that are part of the form:: + >>> from django import forms >>> class ContactForm(forms.Form): ... date = DateField(widget=CalendarWidget) ... name = CharField(max_length=40, widget=OtherWidget) diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index e58dade736..4c46c6c0c0 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -23,6 +23,7 @@ class from a Django model. For example:: >>> from django.forms import ModelForm + >>> from myapp.models import Article # Create the form class. >>> class ArticleForm(ModelForm): @@ -74,7 +75,7 @@ Model field Form field ``FileField`` ``FileField`` -``FilePathField`` ``CharField`` +``FilePathField`` ``FilePathField`` ``FloatField`` ``FloatField`` @@ -222,6 +223,9 @@ supplied, ``save()`` will update that instance. If it's not supplied, .. code-block:: python + >>> from myapp.models import Article + >>> from myapp.forms import ArticleForm + # Create a form instance from POST data. >>> f = ArticleForm(request.POST) @@ -316,6 +320,8 @@ these security concerns do not apply to you: 1. Set the ``fields`` attribute to the special value ``'__all__'`` to indicate that all fields in the model should be used. For example:: + from django.forms import ModelForm + class AuthorForm(ModelForm): class Meta: model = Author @@ -401,6 +407,7 @@ of its default ``<input type="text">``, you can override the field's widget:: from django.forms import ModelForm, Textarea + from myapp.models import Author class AuthorForm(ModelForm): class Meta: @@ -421,6 +428,9 @@ you can do this by declaratively specifying fields like you would in a regular For example, if you wanted to use ``MyDateFormField`` for the ``pub_date`` field, you could do the following:: + from django.forms import ModelForm + from myapp.models import Article + class ArticleForm(ModelForm): pub_date = MyDateFormField() @@ -432,6 +442,9 @@ field, you could do the following:: If you want to override a field's default label, then specify the ``label`` parameter when declaring the form field:: + from django.forms import ModelForm, DateField + from myapp.models import Article + class ArticleForm(ModelForm): pub_date = DateField(label='Publication date') @@ -474,6 +487,26 @@ parameter when declaring the form field:: See the :doc:`form field documentation </ref/forms/fields>` for more information on fields and their arguments. + +Enabling localization of fields +------------------------------- + +.. versionadded:: 1.6 + +By default, the fields in a ``ModelForm`` will not localize their data. To +enable localization for fields, you can use the ``localized_fields`` +attribute on the ``Meta`` class. + + >>> from django.forms import ModelForm + >>> from myapp.models import Author + >>> class AuthorForm(ModelForm): + ... class Meta: + ... model = Author + ... localized_fields = ('birth_date',) + +If ``localized_fields`` is set to the special value ``'__all__'``, all fields +will be localized. + .. _overriding-modelform-clean-method: Overriding the clean() method @@ -556,6 +589,7 @@ definition. This may be more convenient if you do not have many customizations to make:: >>> from django.forms.models import modelform_factory + >>> from myapp.models import Book >>> BookForm = modelform_factory(Book, fields=("author", "title")) This can also be used to make simple modifications to existing forms, for @@ -570,6 +604,10 @@ keyword arguments, or the corresponding attributes on the ``ModelForm`` inner ``Meta`` class. Please see the ``ModelForm`` :ref:`modelforms-selecting-fields` documentation. +... or enable localization for specific fields:: + + >>> Form = modelform_factory(Author, form=AuthorForm, localized_fields=("birth_date",)) + .. _model-formsets: Model formsets @@ -582,6 +620,7 @@ of enhanced formset classes that make it easy to work with Django models. Let's reuse the ``Author`` model from above:: >>> from django.forms.models import modelformset_factory + >>> from myapp.models import Author >>> AuthorFormSet = modelformset_factory(Author) This will create a formset that is capable of working with the data associated @@ -620,6 +659,7 @@ Alternatively, you can create a subclass that sets ``self.queryset`` in ``__init__``:: from django.forms.models import BaseModelFormSet + from myapp.models import Author class BaseAuthorFormSet(BaseModelFormSet): def __init__(self, *args, **kwargs): @@ -663,6 +703,20 @@ class of a ``ModelForm`` works:: >>> AuthorFormSet = modelformset_factory( ... Author, widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20}) +Enabling localization for fields with ``localized_fields`` +---------------------------------------------------------- + +.. versionadded:: 1.6 + +Using the ``localized_fields`` parameter, you can enable localization for +fields in the form. + + >>> AuthorFormSet = modelformset_factory( + ... Author, localized_fields=('value',)) + +If ``localized_fields`` is set to the special value ``'__all__'``, all fields +will be localized. + Providing initial values ------------------------ @@ -751,6 +805,10 @@ Using a model formset in a view Model formsets are very similar to formsets. Let's say we want to present a formset to edit ``Author`` model instances:: + from django.forms.models import modelformset_factory + from django.shortcuts import render_to_response + from myapp.models import Author + def manage_authors(request): AuthorFormSet = modelformset_factory(Author) if request.method == 'POST': @@ -779,12 +837,15 @@ the unique constraints on your model (either ``unique``, ``unique_together`` or on a ``model_formset`` and maintain this validation, you must call the parent class's ``clean`` method:: + from django.forms.models import BaseModelFormSet + class MyModelFormSet(BaseModelFormSet): def clean(self): super(MyModelFormSet, self).clean() # example custom validation across forms in the formset: for form in self.forms: # your custom formset validation + pass Using a custom queryset ----------------------- @@ -792,6 +853,10 @@ Using a custom queryset As stated earlier, you can override the default queryset used by the model formset:: + from django.forms.models import modelformset_factory + from django.shortcuts import render_to_response + from myapp.models import Author + def manage_authors(request): AuthorFormSet = modelformset_factory(Author) if request.method == "POST": @@ -878,6 +943,8 @@ Inline formsets is a small abstraction layer on top of model formsets. These simplify the case of working with related objects via a foreign key. Suppose you have these two models:: + from django.db import models + class Author(models.Model): name = models.CharField(max_length=100) diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt index 80bd5f3c44..54d748d961 100644 --- a/docs/topics/http/file-uploads.txt +++ b/docs/topics/http/file-uploads.txt @@ -15,6 +15,7 @@ Basic file uploads Consider a simple form containing a :class:`~django.forms.FileField`:: + # In forms.py... from django import forms class UploadFileForm(forms.Form): @@ -39,6 +40,7 @@ something like:: from django.http import HttpResponseRedirect from django.shortcuts import render_to_response + from .forms import UploadFileForm # Imaginary function to handle an uploaded file. from somewhere import handle_uploaded_file diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt index acad61eb2a..772ee122d5 100644 --- a/docs/topics/http/sessions.txt +++ b/docs/topics/http/sessions.txt @@ -120,11 +120,29 @@ and the :setting:`SECRET_KEY` setting. .. note:: + When using cookies-based sessions :mod:`django.contrib.sessions` can be + removed from :setting:`INSTALLED_APPS` setting because data is loaded + from the key itself and not from the database, so there is no need for the + creation and usage of ``django.contrib.sessions.models.Session`` table. + +.. note:: + It's recommended to leave the :setting:`SESSION_COOKIE_HTTPONLY` setting ``True`` to prevent tampering of the stored data from JavaScript. .. warning:: + **If the SECRET_KEY is not kept secret, this can lead to arbitrary remote + code execution.** + + An attacker in possession of the :setting:`SECRET_KEY` can not only + generate falsified session data, which your site will trust, but also + remotely execute arbitrary code, as the data is serialized using pickle. + + If you use cookie-based sessions, pay extra care that your secret key is + always kept completely secret, for any system which might be remotely + accessible. + **The session data is signed but not encrypted** When using the cookies backend the session data can be read by the client. diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt index 9a96199dba..8a3f240307 100644 --- a/docs/topics/http/urls.txt +++ b/docs/topics/http/urls.txt @@ -123,6 +123,8 @@ is ``(?P<name>pattern)``, where ``name`` is the name of the group and Here's the above example URLconf, rewritten to use named groups:: + from django.conf.urls import patterns, url + urlpatterns = patterns('', url(r'^articles/2003/$', 'news.views.special_case_2003'), url(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), @@ -192,6 +194,8 @@ A convenient trick is to specify default parameters for your views' arguments. Here's an example URLconf and view:: # URLconf + from django.conf.urls import patterns, url + urlpatterns = patterns('', url(r'^blog/$', 'blog.views.page'), url(r'^blog/page(?P<num>\d+)/$', 'blog.views.page'), @@ -370,11 +374,15 @@ An included URLconf receives any captured parameters from parent URLconfs, so the following example is valid:: # In settings/urls/main.py + from django.conf.urls import include, patterns, url + urlpatterns = patterns('', url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')), ) # In foo/urls/blog.py + from django.conf.urls import patterns, url + urlpatterns = patterns('foo.views', url(r'^$', 'blog.index'), url(r'^archive/$', 'blog.archive'), @@ -397,6 +405,8 @@ function. For example:: + from django.conf.urls import patterns, url + urlpatterns = patterns('blog.views', url(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}), ) @@ -427,11 +437,15 @@ For example, these two URLconf sets are functionally identical: Set one:: # main.py + from django.conf.urls import include, patterns, url + urlpatterns = patterns('', url(r'^blog/', include('inner'), {'blogid': 3}), ) # inner.py + from django.conf.urls import patterns, url + urlpatterns = patterns('', url(r'^archive/$', 'mysite.views.archive'), url(r'^about/$', 'mysite.views.about'), @@ -440,11 +454,15 @@ Set one:: Set two:: # main.py + from django.conf.urls import include, patterns, url + urlpatterns = patterns('', url(r'^blog/', include('inner')), ) # inner.py + from django.conf.urls import patterns, url + urlpatterns = patterns('', url(r'^archive/$', 'mysite.views.archive', {'blogid': 3}), url(r'^about/$', 'mysite.views.about', {'blogid': 3}), @@ -464,6 +482,8 @@ supported -- you can pass any callable object as the view. For example, given this URLconf in "string" notation:: + from django.conf.urls import patterns, url + urlpatterns = patterns('', url(r'^archive/$', 'mysite.views.archive'), url(r'^about/$', 'mysite.views.about'), @@ -473,6 +493,7 @@ For example, given this URLconf in "string" notation:: You can accomplish the same thing by passing objects rather than strings. Just be sure to import the objects:: + from django.conf.urls import patterns, url from mysite.views import archive, about, contact urlpatterns = patterns('', @@ -485,6 +506,7 @@ The following example is functionally identical. It's just a bit more compact because it imports the module that contains the views, rather than importing each view individually:: + from django.conf.urls import patterns, url from mysite import views urlpatterns = patterns('', @@ -501,6 +523,7 @@ the view prefix (as explained in "The view prefix" above) will have no effect. Note that :doc:`class based views</topics/class-based-views/index>` must be imported:: + from django.conf.urls import patterns, url from mysite.views import ClassBasedView urlpatterns = patterns('', @@ -612,6 +635,9 @@ It's fairly common to use the same view function in multiple URL patterns in your URLconf. For example, these two URL patterns both point to the ``archive`` view:: + from django.conf.urls import patterns, url + from mysite.views import archive + urlpatterns = patterns('', url(r'^archive/(\d{4})/$', archive), url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}), @@ -630,6 +656,9 @@ matching. Here's the above example, rewritten to use named URL patterns:: + from django.conf.urls import patterns, url + from mysite.views import archive + urlpatterns = patterns('', url(r'^archive/(\d{4})/$', archive, name="full-archive"), url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, name="arch-summary"), @@ -803,6 +832,8 @@ However, you can also ``include()`` a 3-tuple containing:: For example:: + from django.conf.urls import include, patterns, url + help_patterns = patterns('', url(r'^basic/$', 'apps.help.views.views.basic'), url(r'^advanced/$', 'apps.help.views.views.advanced'), diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt index f73ec4f5be..5c27c9c958 100644 --- a/docs/topics/http/views.txt +++ b/docs/topics/http/views.txt @@ -70,6 +70,8 @@ documentation. Just return an instance of one of those subclasses instead of a normal :class:`~django.http.HttpResponse` in order to signify an error. For example:: + from django.http import HttpResponse, HttpResponseNotFound + def my_view(request): # ... if foo: @@ -83,6 +85,8 @@ the :class:`~django.http.HttpResponse` documentation, you can also pass the HTTP status code into the constructor for :class:`~django.http.HttpResponse` to create a return class for any status code you like. For example:: + from django.http import HttpResponse + def my_view(request): # ... @@ -110,6 +114,8 @@ standard error page for your application, along with an HTTP error code 404. Example usage:: from django.http import Http404 + from django.shortcuts import render_to_response + from polls.models import Poll def detail(request, poll_id): try: @@ -225,3 +231,25 @@ same way you can for the 404 and 500 views by specifying a ``handler403`` in your URLconf:: handler403 = 'mysite.views.my_custom_permission_denied_view' + +.. _http_bad_request_view: + +The 400 (bad request) view +-------------------------- + +When a :exc:`~django.core.exceptions.SuspiciousOperation` is raised in Django, +the it may be handled by a component of Django (for example resetting the +session data). If not specifically handled, Django will consider the current +request a 'bad request' instead of a server error. + +The view ``django.views.defaults.bad_request``, is otherwise very similar to +the ``server_error`` view, but returns with the status code 400 indicating that +the error condition was the result of a client operation. + +Like the ``server_error`` view, the default ``bad_request`` should suffice for +99% of Web applications, but if you want to override the view, you can specify +``handler400`` in your URLconf, like so:: + + handler400 = 'mysite.views.my_custom_bad_request_view' + +``bad_request`` views are also only used when :setting:`DEBUG` is ``False``. diff --git a/docs/topics/i18n/timezones.txt b/docs/topics/i18n/timezones.txt index e4a043b08f..5ed60d0a94 100644 --- a/docs/topics/i18n/timezones.txt +++ b/docs/topics/i18n/timezones.txt @@ -54,6 +54,8 @@ FAQ <time-zones-faq>`. Concepts ======== +.. _naive_vs_aware_datetimes: + Naive and aware datetime objects -------------------------------- diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index 5b4ffea528..ce6697908f 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -80,6 +80,7 @@ In this example, the text ``"Welcome to my site."`` is marked as a translation string:: from django.utils.translation import ugettext as _ + from django.http import HttpResponse def my_view(request): output = _("Welcome to my site.") @@ -89,6 +90,7 @@ Obviously, you could code this without using the alias. This example is identical to the previous one:: from django.utils.translation import ugettext + from django.http import HttpResponse def my_view(request): output = ugettext("Welcome to my site.") @@ -192,6 +194,7 @@ of its value.) For example:: from django.utils.translation import ungettext + from django.http import HttpResponse def hello_world(request, count): page = ungettext( @@ -208,6 +211,7 @@ languages as the ``count`` variable. Lets see a slightly more complex usage example:: from django.utils.translation import ungettext + from myapp.models import Report count = Report.objects.count() if count == 1: @@ -283,6 +287,7 @@ For example:: or:: + from django.db import models from django.utils.translation import pgettext_lazy class MyThing(models.Model): @@ -328,6 +333,7 @@ Model fields and relationships ``verbose_name`` and ``help_text`` option values For example, to translate the help text of the *name* field in the following model, do the following:: + from django.db import models from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): @@ -336,8 +342,6 @@ model, do the following:: You can mark names of ``ForeignKey``, ``ManyTomanyField`` or ``OneToOneField`` relationship as translatable by using their ``verbose_name`` options:: - from django.utils.translation import ugettext_lazy as _ - class MyThing(models.Model): kind = models.ForeignKey(ThingKind, related_name='kinds', verbose_name=_('kind')) @@ -355,6 +359,7 @@ It is recommended to always provide explicit relying on the fallback English-centric and somewhat naïve determination of verbose names Django performs by looking at the model's class name:: + from django.db import models from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): @@ -370,6 +375,7 @@ Model methods ``short_description`` attribute values For model methods, you can provide translations to Django and the admin site with the ``short_description`` attribute:: + from django.db import models from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): @@ -404,6 +410,7 @@ If you ever see output that looks like ``"hello If you don't like the long ``ugettext_lazy`` name, you can just alias it as ``_`` (underscore), like so:: + from django.db import models from django.utils.translation import ugettext_lazy as _ class MyThing(models.Model): @@ -429,6 +436,9 @@ definition. Therefore, you are authorized to pass a key name instead of an integer as the ``number`` argument. Then ``number`` will be looked up in the dictionary under that key during string interpolation. Here's example:: + from django import forms + from django.utils.translation import ugettext_lazy + class MyForm(forms.Form): error_message = ungettext_lazy("You only provided %(num)d argument", "You only provided %(num)d arguments", 'num') @@ -461,6 +471,7 @@ that concatenates its contents *and* converts them to strings only when the result is included in a string. For example:: from django.utils.translation import string_concat + from django.utils.translation import ugettext_lazy ... name = ugettext_lazy('John Lennon') instrument = ugettext_lazy('guitar') @@ -687,7 +698,7 @@ or with the ``{#`` ... ``#}`` :ref:`one-line comment constructs <template-commen .. code-block:: html+django - {# Translators: Label of a button that triggers search{% endcomment #} + {# Translators: Label of a button that triggers search #} <button type="submit">{% trans "Go" %}</button> {# Translators: This is a text of the base template #} @@ -722,6 +733,31 @@ or with the ``{#`` ... ``#}`` :ref:`one-line comment constructs <template-commen msgid "Ambiguous translatable block of text" msgstr "" +.. templatetag:: language + +Switching language in templates +------------------------------- + +If you want to select a language within a template, you can use the +``language`` template tag: + +.. code-block:: html+django + + {% load i18n %} + + {% get_current_language as LANGUAGE_CODE %} + <!-- Current language: {{ LANGUAGE_CODE }} --> + <p>{% trans "Welcome to our page" %}</p> + + {% language 'en' %} + {% get_current_language as LANGUAGE_CODE %} + <!-- Current language: {{ LANGUAGE_CODE }} --> + <p>{% trans "Welcome to our page" %}</p> + {% endlanguage %} + +While the first occurrence of "Welcome to our page" uses the current language, +the second will always be in English. + .. _template-translation-vars: Other tags @@ -1126,13 +1162,11 @@ active language. Example:: .. _reversing_in_templates: -.. templatetag:: language - Reversing in templates ---------------------- If localized URLs get reversed in templates they always use the current -language. To link to a URL in another language use the ``language`` +language. To link to a URL in another language use the :ttag:`language` template tag. It enables the given language in the enclosed template section: .. code-block:: html+django @@ -1640,6 +1674,8 @@ preference available as ``request.LANGUAGE_CODE`` for each :class:`~django.http.HttpRequest`. Feel free to read this value in your view code. Here's a simple example:: + from django.http import HttpResponse + def hello_world(request, count): if request.LANGUAGE_CODE == 'de-at': return HttpResponse("You prefer to read Austrian German.") diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt index a31dc01cc5..a88201ad47 100644 --- a/docs/topics/logging.txt +++ b/docs/topics/logging.txt @@ -394,7 +394,7 @@ requirements of logging in Web server environment. Loggers ------- -Django provides three built-in loggers. +Django provides four built-in loggers. ``django`` ~~~~~~~~~~ @@ -434,6 +434,35 @@ For performance reasons, SQL logging is only enabled when ``settings.DEBUG`` is set to ``True``, regardless of the logging level or handlers that are installed. +``django.security.*`` +~~~~~~~~~~~~~~~~~~~~~~ + +The security loggers will receive messages on any occurrence of +:exc:`~django.core.exceptions.SuspiciousOperation`. There is a sub-logger for +each sub-type of SuspiciousOperation. The level of the log event depends on +where the exception is handled. Most occurrences are logged as a warning, while +any ``SuspiciousOperation`` that reaches the WSGI handler will be logged as an +error. For example, when an HTTP ``Host`` header is included in a request from +a client that does not match :setting:`ALLOWED_HOSTS`, Django will return a 400 +response, and an error message will be logged to the +``django.security.DisallowedHost`` logger. + +Only the parent ``django.security`` logger is configured by default, and all +child loggers will propagate to the parent logger. The ``django.security`` +logger is configured the same as the ``django.request`` logger, and any error +events will be mailed to admins. Requests resulting in a 400 response due to +a ``SuspiciousOperation`` will not be logged to the ``django.request`` logger, +but only to the ``django.security`` logger. + +To silence a particular type of SuspiciousOperation, you can override that +specific logger following this example:: + + 'loggers': { + 'django.security.DisallowedHost': { + 'handlers': ['null'], + 'propagate': False, + }, + Handlers -------- diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt index 22e609c75c..9a0438e9e5 100644 --- a/docs/topics/python3.txt +++ b/docs/topics/python3.txt @@ -201,8 +201,8 @@ According to :pep:`3333`: Specifically, :attr:`HttpResponse.content <django.http.HttpResponse.content>` contains ``bytes``, which may become an issue if you compare it with a ``str`` in your tests. The preferred solution is to rely on -:meth:`~django.test.TestCase.assertContains` and -:meth:`~django.test.TestCase.assertNotContains`. These methods accept a +:meth:`~django.test.SimpleTestCase.assertContains` and +:meth:`~django.test.SimpleTestCase.assertNotContains`. These methods accept a response and a unicode string as arguments. Coding guidelines diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt index cefb770469..b7f49d2b97 100644 --- a/docs/topics/testing/advanced.txt +++ b/docs/topics/testing/advanced.txt @@ -113,7 +113,8 @@ two databases. Controlling creation order for test databases --------------------------------------------- -By default, Django will always create the ``default`` database first. +By default, Django will assume all databases depend on the ``default`` +database and therefore always create the ``default`` database first. However, no guarantees are made on the creation order of any other databases in your test setup. @@ -129,6 +130,7 @@ can specify the dependencies that exist using the }, 'diamonds': { # ... db settings + 'TEST_DEPENDENCIES': [] }, 'clubs': { # ... db settings diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt index fc2b393898..2b1db5e501 100644 --- a/docs/topics/testing/overview.txt +++ b/docs/topics/testing/overview.txt @@ -21,17 +21,16 @@ module defines tests using a class-based approach. .. admonition:: unittest2 - Python 2.7 introduced some major changes to the unittest library, + Python 2.7 introduced some major changes to the ``unittest`` library, adding some extremely useful features. To ensure that every Django project can benefit from these new features, Django ships with a - copy of unittest2_, a copy of the Python 2.7 unittest library, - backported for Python 2.6 compatibility. + copy of unittest2_, a copy of Python 2.7's ``unittest``, backported for + Python 2.6 compatibility. To access this library, Django provides the ``django.utils.unittest`` module alias. If you are using Python - 2.7, or you have installed unittest2 locally, Django will map the - alias to the installed version of the unittest library. Otherwise, - Django will use its own bundled version of unittest2. + 2.7, or you have installed ``unittest2`` locally, Django will map the alias + to it. Otherwise, Django will use its own bundled version of ``unittest2``. To use this alias, simply use:: @@ -41,8 +40,8 @@ module defines tests using a class-based approach. import unittest - If you want to continue to use the base unittest library, you can -- - you just won't get any of the nice new unittest2 features. + If you want to continue to use the legacy ``unittest`` library, you can -- + you just won't get any of the nice new ``unittest2`` features. .. _unittest2: http://pypi.python.org/pypi/unittest2 @@ -697,7 +696,7 @@ Use the ``django.test.client.Client`` class to make requests. After you call this method, the test client will have all the cookies and session data cleared to defaults. Subsequent requests will appear - to come from an AnonymousUser. + to come from an :class:`~django.contrib.auth.models.AnonymousUser`. Testing responses ~~~~~~~~~~~~~~~~~ @@ -858,24 +857,46 @@ SimpleTestCase .. class:: SimpleTestCase() -A very thin subclass of :class:`unittest.TestCase`, it extends it with some -basic functionality like: +A thin subclass of :class:`unittest.TestCase`, it extends it with some basic +functionality like: * Saving and restoring the Python warning machinery state. -* Checking that a callable :meth:`raises a certain exception <SimpleTestCase.assertRaisesMessage>`. -* :meth:`Testing form field rendering <SimpleTestCase.assertFieldOutput>`. -* Testing server :ref:`HTML responses for the presence/lack of a given fragment <assertions>`. -* The ability to run tests with :ref:`modified settings <overriding-settings>` +* Some useful assertions like: + + * Checking that a callable :meth:`raises a certain exception + <SimpleTestCase.assertRaisesMessage>`. + * Testing form field :meth:`rendering and error treatment + <SimpleTestCase.assertFieldOutput>`. + * Testing :meth:`HTML responses for the presence/lack of a given fragment + <SimpleTestCase.assertContains>`. + * Verifying that a template :meth:`has/hasn't been used to generate a given + response content <SimpleTestCase.assertTemplateUsed>`. + * Verifying a HTTP :meth:`redirect <SimpleTestCase.assertRedirects>` is + performed by the app. + * Robustly testing two :meth:`HTML fragments <SimpleTestCase.assertHTMLEqual>` + for equality/inequality or :meth:`containment <SimpleTestCase.assertInHTML>`. + * Robustly testing two :meth:`XML fragments <SimpleTestCase.assertXMLEqual>` + for equality/inequality. + * Robustly testing two :meth:`JSON fragments <SimpleTestCase.assertJSONEqual>` + for equality. + +* The ability to run tests with :ref:`modified settings <overriding-settings>`. +* Using the :attr:`~SimpleTestCase.client` :class:`~django.test.client.Client`. +* Custom test-time :attr:`URL maps <SimpleTestCase.urls>`. + +.. versionchanged:: 1.6 + + The latter two features were moved from ``TransactionTestCase`` to + ``SimpleTestCase`` in Django 1.6. If you need any of the other more complex and heavyweight Django-specific features like: -* Using the :attr:`~TestCase.client` :class:`~django.test.client.Client`. * Testing or using the ORM. -* Database :attr:`~TestCase.fixtures`. -* Custom test-time :attr:`URL maps <TestCase.urls>`. +* Database :attr:`~TransactionTestCase.fixtures`. * Test :ref:`skipping based on database backend features <skipping-tests>`. -* The remaining specialized :ref:`assert* <assertions>` methods. +* The remaining specialized :meth:`assert* + <TransactionTestCase.assertQuerysetEqual>` methods. then you should use :class:`~django.test.TransactionTestCase` or :class:`~django.test.TestCase` instead. @@ -904,14 +925,23 @@ to test the effects of commit and rollback: * A ``TestCase``, on the other hand, does not truncate tables after a test. Instead, it encloses the test code in a database transaction that is rolled - back at the end of the test. It also prevents the code under test from - issuing any commit or rollback operations on the database, to ensure that the - rollback at the end of the test restores the database to its initial state. + back at the end of the test. Both explicit commits like + ``transaction.commit()`` and implicit ones that may be caused by + ``Model.save()`` are replaced with a ``nop`` operation. This guarantees that + the rollback at the end of the test restores the database to its initial + state. When running on a database that does not support rollback (e.g. MySQL with the MyISAM storage engine), ``TestCase`` falls back to initializing the database by truncating tables and reloading initial data. +.. warning:: + + While ``commit`` and ``rollback`` operations still *appear* to work when + used in ``TestCase``, no actual commit or rollback will be performed by the + database. This can cause your tests to pass or fail unexpectedly. Always + use ``TransactionalTestCase`` when testing transactional behavior. + .. note:: .. versionchanged:: 1.5 @@ -923,7 +953,7 @@ to test the effects of commit and rollback: key values started at one in :class:`~django.test.TransactionTestCase` tests. - Tests should not depend on this behaviour, but for legacy tests that do, the + Tests should not depend on this behavior, but for legacy tests that do, the :attr:`~TransactionTestCase.reset_sequences` attribute can be used until the test has been properly updated. @@ -1137,9 +1167,9 @@ Test cases features Default test client ~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.client +.. attribute:: SimpleTestCase.client -Every test case in a ``django.test.TestCase`` instance has access to an +Every test case in a ``django.test.*TestCase`` instance has access to an instance of a Django test client. This client can be accessed as ``self.client``. This client is recreated for each test, so you don't have to worry about state (such as cookies) carrying over from one test to another. @@ -1176,10 +1206,10 @@ This means, instead of instantiating a ``Client`` in each test:: Customizing the test client ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.client_class +.. attribute:: SimpleTestCase.client_class If you want to use a different ``Client`` class (for example, a subclass -with customized behavior), use the :attr:`~TestCase.client_class` class +with customized behavior), use the :attr:`~SimpleTestCase.client_class` class attribute:: from django.test import TestCase @@ -1200,11 +1230,12 @@ attribute:: Fixture loading ~~~~~~~~~~~~~~~ -.. attribute:: TestCase.fixtures +.. attribute:: TransactionTestCase.fixtures A test case for a database-backed Web site isn't much use if there isn't any data in the database. To make it easy to put test data into the database, -Django's custom ``TestCase`` class provides a way of loading **fixtures**. +Django's custom ``TransactionTestCase`` class provides a way of loading +**fixtures**. A fixture is a collection of data that Django knows how to import into a database. For example, if your site has user accounts, you might set up a @@ -1273,7 +1304,7 @@ or by the order of test execution. URLconf configuration ~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.urls +.. attribute:: SimpleTestCase.urls If your application provides views, you may want to include tests that use the test client to exercise those views. However, an end user is free to deploy the @@ -1282,9 +1313,9 @@ tests can't rely upon the fact that your views will be available at a particular URL. In order to provide a reliable URL space for your test, -``django.test.TestCase`` provides the ability to customize the URLconf +``django.test.*TestCase`` classes provide the ability to customize the URLconf configuration for the duration of the execution of a test suite. If your -``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` will use +``*TestCase`` instance defines an ``urls`` attribute, the ``*TestCase`` will use the value of that attribute as the :setting:`ROOT_URLCONF` for the duration of that test. @@ -1307,7 +1338,7 @@ URLconf for the duration of the test case. Multi-database support ~~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.multi_db +.. attribute:: TransactionTestCase.multi_db Django sets up a test database corresponding to every database that is defined in the :setting:`DATABASES` definition in your settings @@ -1340,12 +1371,12 @@ This test case will flush *all* the test databases before running Overriding settings ~~~~~~~~~~~~~~~~~~~ -.. method:: TestCase.settings +.. method:: SimpleTestCase.settings For testing purposes it's often useful to change a setting temporarily and revert to the original value after running the testing code. For this use case Django provides a standard Python context manager (see :pep:`343`) -:meth:`~django.test.TestCase.settings`, which can be used like this:: +:meth:`~django.test.SimpleTestCase.settings`, which can be used like this:: from django.test import TestCase @@ -1435,8 +1466,8 @@ MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage Emptying the test outbox ~~~~~~~~~~~~~~~~~~~~~~~~ -If you use Django's custom ``TestCase`` class, the test runner will clear the -contents of the test email outbox at the start of each test case. +If you use any of Django's custom ``TestCase`` classes, the test runner will +clear thecontents of the test email outbox at the start of each test case. For more detail on email services during tests, see `Email services`_ below. @@ -1486,8 +1517,43 @@ your test suite. self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid email address.']}) +.. method:: SimpleTestCase.assertFormError(response, form, field, errors, msg_prefix='') + + Asserts that a field on a form raises the provided list of errors when + rendered on the form. + + ``form`` is the name the ``Form`` instance was given in the template + context. + + ``field`` is the name of the field on the form to check. If ``field`` + has a value of ``None``, non-field errors (errors you can access via + ``form.non_field_errors()``) will be checked. + + ``errors`` is an error string, or a list of error strings, that are + expected as a result of form validation. + +.. method:: SimpleTestCase.assertFormsetError(response, formset, form_index, field, errors, msg_prefix='') + + .. versionadded:: 1.6 + + Asserts that the ``formset`` raises the provided list of errors when + rendered. + + ``formset`` is the name the ``Formset`` instance was given in the template + context. + + ``form_index`` is the number of the form within the ``Formset``. If + ``form_index`` has a value of ``None``, non-form errors (errors you can + access via ``formset.non_form_errors()``) will be checked. + + ``field`` is the name of the field on the form to check. If ``field`` + has a value of ``None``, non-field errors (errors you can access via + ``form.non_field_errors()``) will be checked. + + ``errors`` is an error string, or a list of error strings, that are + expected as a result of form validation. -.. method:: TestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False) +.. method:: SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False) Asserts that a ``Response`` instance produced the given ``status_code`` and that ``text`` appears in the content of the response. If ``count`` is @@ -1499,7 +1565,7 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. -.. method:: TestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False) +.. method:: SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False) Asserts that a ``Response`` instance produced the given ``status_code`` and that ``text`` does not appears in the content of the response. @@ -1510,22 +1576,7 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. -.. method:: TestCase.assertFormError(response, form, field, errors, msg_prefix='') - - Asserts that a field on a form raises the provided list of errors when - rendered on the form. - - ``form`` is the name the ``Form`` instance was given in the template - context. - - ``field`` is the name of the field on the form to check. If ``field`` - has a value of ``None``, non-field errors (errors you can access via - ``form.non_field_errors()``) will be checked. - - ``errors`` is an error string, or a list of error strings, that are - expected as a result of form validation. - -.. method:: TestCase.assertTemplateUsed(response, template_name, msg_prefix='') +.. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='') Asserts that the template with the given name was used in rendering the response. @@ -1539,15 +1590,15 @@ your test suite. with self.assertTemplateUsed(template_name='index.html'): render_to_string('index.html') -.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='') +.. method:: SimpleTestCase.assertTemplateNotUsed(response, template_name, msg_prefix='') Asserts that the template with the given name was *not* used in rendering the response. You can use this as a context manager in the same way as - :meth:`~TestCase.assertTemplateUsed`. + :meth:`~SimpleTestCase.assertTemplateUsed`. -.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='') +.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='') Asserts that the response return a ``status_code`` redirect status, it redirected to ``expected_url`` (including any GET data), and the final @@ -1557,44 +1608,6 @@ your test suite. ``target_status_code`` will be the url and status code for the final point of the redirect chain. -.. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True) - - Asserts that a queryset ``qs`` returns a particular list of values ``values``. - - The comparison of the contents of ``qs`` and ``values`` is performed using - the function ``transform``; by default, this means that the ``repr()`` of - each value is compared. Any other callable can be used if ``repr()`` doesn't - provide a unique or helpful comparison. - - By default, the comparison is also ordering dependent. If ``qs`` doesn't - provide an implicit ordering, you can set the ``ordered`` parameter to - ``False``, which turns the comparison into a Python set comparison. - - .. versionchanged:: 1.6 - - The method now checks for undefined order and raises ``ValueError`` - if undefined order is spotted. The ordering is seen as undefined if - the given ``qs`` isn't ordered and the comparison is against more - than one ordered values. - -.. method:: TestCase.assertNumQueries(num, func, *args, **kwargs) - - Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that - ``num`` database queries are executed. - - If a ``"using"`` key is present in ``kwargs`` it is used as the database - alias for which to check the number of queries. If you wish to call a - function with a ``using`` parameter you can do it by wrapping the call with - a ``lambda`` to add an extra parameter:: - - self.assertNumQueries(7, lambda: my_function(using=7)) - - You can also use this as a context manager:: - - with self.assertNumQueries(2): - Person.objects.create(name="Aaron") - Person.objects.create(name="Daniel") - .. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None) Asserts that the strings ``html1`` and ``html2`` are equal. The comparison @@ -1624,6 +1637,8 @@ your test suite. ``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be raised if one of them cannot be parsed. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertHTMLNotEqual(html1, html2, msg=None) Asserts that the strings ``html1`` and ``html2`` are *not* equal. The @@ -1633,6 +1648,8 @@ your test suite. ``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be raised if one of them cannot be parsed. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertXMLEqual(xml1, xml2, msg=None) .. versionadded:: 1.5 @@ -1644,6 +1661,8 @@ your test suite. syntax differences. When unvalid XML is passed in any parameter, an ``AssertionError`` is always raised, even if both string are identical. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertXMLNotEqual(xml1, xml2, msg=None) .. versionadded:: 1.5 @@ -1652,6 +1671,68 @@ your test suite. comparison is based on XML semantics. See :meth:`~SimpleTestCase.assertXMLEqual` for details. + Output in case of error can be customized with the ``msg`` argument. + +.. method:: SimpleTestCase.assertInHTML(needle, haystack, count=None, msg_prefix='') + + .. versionadded:: 1.5 + + Asserts that the HTML fragment ``needle`` is contained in the ``haystack`` one. + + If the ``count`` integer argument is specified, then additionally the number + of ``needle`` occurrences will be strictly verified. + + Whitespace in most cases is ignored, and attribute ordering is not + significant. The passed-in arguments must be valid HTML. + +.. method:: SimpleTestCase.assertJSONEqual(raw, expected_data, msg=None) + + .. versionadded:: 1.5 + + Asserts that the JSON fragments ``raw`` and ``expected_data`` are equal. + Usual JSON non-significant whitespace rules apply as the heavyweight is + delegated to the :mod:`json` library. + + Output in case of error can be customized with the ``msg`` argument. + +.. method:: TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True) + + Asserts that a queryset ``qs`` returns a particular list of values ``values``. + + The comparison of the contents of ``qs`` and ``values`` is performed using + the function ``transform``; by default, this means that the ``repr()`` of + each value is compared. Any other callable can be used if ``repr()`` doesn't + provide a unique or helpful comparison. + + By default, the comparison is also ordering dependent. If ``qs`` doesn't + provide an implicit ordering, you can set the ``ordered`` parameter to + ``False``, which turns the comparison into a Python set comparison. + + .. versionchanged:: 1.6 + + The method now checks for undefined order and raises ``ValueError`` + if undefined order is spotted. The ordering is seen as undefined if + the given ``qs`` isn't ordered and the comparison is against more + than one ordered values. + +.. method:: TransactionTestCase.assertNumQueries(num, func, *args, **kwargs) + + Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that + ``num`` database queries are executed. + + If a ``"using"`` key is present in ``kwargs`` it is used as the database + alias for which to check the number of queries. If you wish to call a + function with a ``using`` parameter you can do it by wrapping the call with + a ``lambda`` to add an extra parameter:: + + self.assertNumQueries(7, lambda: my_function(using=7)) + + You can also use this as a context manager:: + + with self.assertNumQueries(2): + Person.objects.create(name="Aaron") + Person.objects.create(name="Daniel") + .. _topics-testing-email: Email services @@ -1701,7 +1782,7 @@ and contents:: self.assertEqual(mail.outbox[0].subject, 'Subject here') As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied -at the start of every test in a Django ``TestCase``. To empty the outbox +at the start of every test in a Django ``*TestCase``. To empty the outbox manually, assign the empty list to ``mail.outbox``:: from django.core import mail |
