summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/conf.py12
-rw-r--r--docs/faq/general.txt2
-rw-r--r--docs/howto/custom-template-tags.txt6
-rw-r--r--docs/howto/deployment/wsgi/gunicorn.txt2
-rw-r--r--docs/index.txt9
-rw-r--r--docs/internals/committers.txt4
-rw-r--r--docs/internals/contributing/bugs-and-features.txt2
-rw-r--r--docs/intro/tutorial03.txt11
-rw-r--r--docs/ref/class-based-views/base.txt35
-rw-r--r--docs/ref/class-based-views/flattened-index.txt556
-rw-r--r--docs/ref/class-based-views/generic-date-based.txt27
-rw-r--r--docs/ref/class-based-views/generic-display.txt10
-rw-r--r--docs/ref/class-based-views/generic-editing.txt27
-rw-r--r--docs/ref/class-based-views/index.txt3
-rw-r--r--docs/ref/class-based-views/mixins-date-based.txt18
-rw-r--r--docs/ref/class-based-views/mixins-editing.txt14
-rw-r--r--docs/ref/class-based-views/mixins-multiple-object.txt6
-rw-r--r--docs/ref/class-based-views/mixins-simple.txt22
-rw-r--r--docs/ref/class-based-views/mixins-single-object.txt6
-rw-r--r--docs/ref/contrib/admin/index.txt8
-rw-r--r--docs/ref/contrib/comments/index.txt4
-rw-r--r--docs/ref/contrib/csrf.txt147
-rw-r--r--docs/ref/contrib/flatpages.txt43
-rw-r--r--docs/ref/contrib/formtools/form-wizard.txt6
-rw-r--r--docs/ref/contrib/gis/install.txt42
-rw-r--r--docs/ref/contrib/gis/testing.txt5
-rw-r--r--docs/ref/contrib/gis/tutorial.txt11
-rw-r--r--docs/ref/databases.txt8
-rw-r--r--docs/ref/files/file.txt12
-rw-r--r--docs/ref/models/fields.txt92
-rw-r--r--docs/ref/models/instances.txt12
-rw-r--r--docs/ref/models/querysets.txt16
-rw-r--r--docs/ref/request-response.txt19
-rw-r--r--docs/ref/settings.txt41
-rw-r--r--docs/ref/templates/api.txt10
-rw-r--r--docs/ref/utils.txt92
-rw-r--r--docs/releases/1.3.2.txt14
-rw-r--r--docs/releases/1.4.1.txt14
-rw-r--r--docs/releases/1.4.2.txt14
-rw-r--r--docs/releases/1.5.txt93
-rw-r--r--docs/releases/index.txt3
-rw-r--r--docs/topics/auth.txt21
-rw-r--r--docs/topics/cache.txt2
-rw-r--r--docs/topics/class-based-views/index.txt149
-rw-r--r--docs/topics/class-based-views/mixins.txt150
-rw-r--r--docs/topics/db/models.txt28
-rw-r--r--docs/topics/db/multi-db.txt2
-rw-r--r--docs/topics/db/queries.txt4
-rw-r--r--docs/topics/forms/media.txt60
-rw-r--r--docs/topics/forms/modelforms.txt4
-rw-r--r--docs/topics/http/file-uploads.txt46
-rw-r--r--docs/topics/http/urls.txt12
-rw-r--r--docs/topics/http/views.txt4
-rw-r--r--docs/topics/i18n/translation.txt22
-rw-r--r--docs/topics/logging.txt38
-rw-r--r--docs/topics/python3.txt308
-rw-r--r--docs/topics/templates.txt6
-rw-r--r--docs/topics/testing.txt2
58 files changed, 1869 insertions, 467 deletions
diff --git a/docs/conf.py b/docs/conf.py
index 39a280e464..433fd679a1 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -190,11 +190,10 @@ modindex_common_prefix = ["django."]
# -- Options for LaTeX output --------------------------------------------------
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
+latex_elements = {
+ 'preamble': ('\\DeclareUnicodeCharacter{2264}{\\ensuremath{\\le}}'
+ '\\DeclareUnicodeCharacter{2265}{\\ensuremath{\\ge}}')
+}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
@@ -218,9 +217,6 @@ latex_documents = [
# If true, show URL addresses after external links.
#latex_show_urls = False
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
# Documents to append as an appendix to all manuals.
#latex_appendices = []
diff --git a/docs/faq/general.txt b/docs/faq/general.txt
index 771af8a2cc..659a8c5ad9 100644
--- a/docs/faq/general.txt
+++ b/docs/faq/general.txt
@@ -185,6 +185,6 @@ would be happy to help you.
You might also be interested in posting a job to http://djangogigs.com/ .
If you want to find Django-capable people in your local area, try
-http://djangopeople.net/ .
+https://people.djangoproject.com/ .
.. _developers for hire page: https://code.djangoproject.com/wiki/DevelopersForHire
diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt
index 054c831fad..5b27af82d6 100644
--- a/docs/howto/custom-template-tags.txt
+++ b/docs/howto/custom-template-tags.txt
@@ -189,7 +189,7 @@ passed around inside the template code:
They're commonly used for output that contains raw HTML that is intended
to be interpreted as-is on the client side.
- Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
+ Internally, these strings are of type ``SafeBytes`` or ``SafeText``.
They share a common base class of ``SafeData``, so you can test
for them using code like:
@@ -204,8 +204,8 @@ passed around inside the template code:
not. These strings are only escaped once, however, even if auto-escaping
applies.
- Internally, these strings are of type ``EscapeString`` or
- ``EscapeUnicode``. Generally you don't have to worry about these; they
+ Internally, these strings are of type ``EscapeBytes`` or
+ ``EscapeText``. Generally you don't have to worry about these; they
exist for the implementation of the :tfilter:`escape` filter.
Template filter code falls into one of two situations:
diff --git a/docs/howto/deployment/wsgi/gunicorn.txt b/docs/howto/deployment/wsgi/gunicorn.txt
index 13d4043e37..c4483291a3 100644
--- a/docs/howto/deployment/wsgi/gunicorn.txt
+++ b/docs/howto/deployment/wsgi/gunicorn.txt
@@ -13,7 +13,7 @@ There are two ways to use Gunicorn with Django. One is to have Gunicorn treat
Django as just another WSGI application. The second is to use Gunicorn's
special `integration with Django`_.
-.. _integration with Django: http://gunicorn.org/run.html#django-manage-py_
+.. _integration with Django: http://gunicorn.org/run.html#django-manage-py
Installing Gunicorn
===================
diff --git a/docs/index.txt b/docs/index.txt
index 011ecdb0bc..3f4e30385c 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -104,9 +104,12 @@ to know about views via the links below:
:doc:`Custom storage <howto/custom-file-storage>`
* **Class-based views:**
- :doc:`Overview<topics/class-based-views/index>` |
- :doc:`Built-in class-based views<ref/class-based-views/index>` |
- :doc:`Built-in view mixins<ref/class-based-views/mixins>`
+ :doc:`Overview <topics/class-based-views/index>` |
+ :doc:`Built-in display views <topics/class-based-views/generic-display>` |
+ :doc:`Built-in editing views <topics/class-based-views/generic-editing>` |
+ :doc:`Using mixins <topics/class-based-views/mixins>` |
+ :doc:`API reference <ref/class-based-views/index>` |
+ :doc:`Flattened index<ref/class-based-views/flattened-index>`
* **Advanced:**
:doc:`Generating CSV <howto/outputting-csv>` |
diff --git a/docs/internals/committers.txt b/docs/internals/committers.txt
index 5567c26fa1..2faace99a5 100644
--- a/docs/internals/committers.txt
+++ b/docs/internals/committers.txt
@@ -77,7 +77,7 @@ record of being helpful on the mailing lists, and a proven desire to dedicate
serious time to Django. In return, they've been granted the coveted commit bit,
and have free rein to hack on all parts of Django.
-`Malcolm Tredinnick`_
+Malcolm Tredinnick
Malcolm originally wanted to be a mathematician, somehow ended up a software
developer. He's contributed to many Open Source projects, has served on the
board of the GNOME foundation, and will kick your ass at chess.
@@ -85,8 +85,6 @@ and have free rein to hack on all parts of Django.
When he's not busy being an International Man of Mystery, Malcolm lives in
Sydney, Australia.
-.. _malcolm tredinnick: http://www.pointy-stick.com/
-
`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
diff --git a/docs/internals/contributing/bugs-and-features.txt b/docs/internals/contributing/bugs-and-features.txt
index 91a078cbc0..53b0e1007d 100644
--- a/docs/internals/contributing/bugs-and-features.txt
+++ b/docs/internals/contributing/bugs-and-features.txt
@@ -62,8 +62,6 @@ To understand the lifecycle of your ticket once you have created it, refer to
.. _django-updates: http://groups.google.com/group/django-updates
-.. _reporting-security-issues:
-
Reporting user interface bugs and features
------------------------------------------
diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt
index d15b2f43ae..6d4fb7eef1 100644
--- a/docs/intro/tutorial03.txt
+++ b/docs/intro/tutorial03.txt
@@ -550,5 +550,16 @@ with the :ttag:`url` template tag:
<li><a href="{% url 'polls.views.detail' poll.id %}">{{ poll.question }}</a></li>
+.. note::
+
+ If ``{% url 'polls.views.detail' poll.id %}`` (with quotes) doesn't work,
+ but ``{% url polls.views.detail poll.id %}`` (without quotes) does, that
+ means you're using a version of Django ≤ 1.4. In this case, add the
+ following declaration at the top of your template:
+
+ .. code-block:: html+django
+
+ {% load url from future %}
+
When you're comfortable with writing views, read :doc:`part 4 of this tutorial
</intro/tutorial04>` to learn about simple form processing and generic views.
diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt
index 5e0360c88f..3f82b44f46 100644
--- a/docs/ref/class-based-views/base.txt
+++ b/docs/ref/class-based-views/base.txt
@@ -8,6 +8,9 @@ themselves or inherited from. They may not provide all the capabilities
required for projects, in which case there are Mixins and Generic class-based
views.
+View
+----
+
.. class:: django.views.generic.base.View
The master class-based base view. All other class-based views inherit from
@@ -31,13 +34,13 @@ views.
**Example urls.py**::
from django.conf.urls import patterns, url
-
+
from myapp.views import MyView
-
+
urlpatterns = patterns('',
url(r'^mine/$', MyView.as_view(), name='my-view'),
)
-
+
**Methods**
.. method:: dispatch(request, *args, **kwargs)
@@ -61,13 +64,16 @@ views.
The default implementation returns ``HttpResponseNotAllowed`` with list
of allowed methods in plain text.
-
- .. note::
+
+ .. note::
Documentation on class-based views is a work in progress. As yet, only the
methods defined directly on the class are documented here, not methods
defined on superclasses.
+TemplateView
+------------
+
.. class:: django.views.generic.base.TemplateView
Renders a given template, passing it a ``{{ params }}`` template variable,
@@ -84,22 +90,22 @@ views.
1. :meth:`dispatch()`
2. :meth:`http_method_not_allowed()`
3. :meth:`get_context_data()`
-
+
**Example views.py**::
from django.views.generic.base import TemplateView
-
+
from articles.models import Article
class HomePageView(TemplateView):
template_name = "home.html"
-
+
def get_context_data(self, **kwargs):
context = super(HomePageView, self).get_context_data(**kwargs)
context['latest_articles'] = Article.objects.all()[:5]
return context
-
+
**Example urls.py**::
from django.conf.urls import patterns, url
@@ -126,12 +132,15 @@ views.
* ``params``: The dictionary of keyword arguments captured from the URL
pattern that served the view.
- .. note::
+ .. note::
Documentation on class-based views is a work in progress. As yet, only the
methods defined directly on the class are documented here, not methods
defined on superclasses.
+RedirectView
+------------
+
.. class:: django.views.generic.base.RedirectView
Redirects to a given URL.
@@ -159,7 +168,7 @@ views.
from django.shortcuts import get_object_or_404
from django.views.generic.base import RedirectView
-
+
from articles.models import Article
class ArticleCounterRedirectView(RedirectView):
@@ -176,7 +185,7 @@ views.
from django.conf.urls import patterns, url
from django.views.generic.base import RedirectView
-
+
from article.views import ArticleCounterRedirectView
urlpatterns = patterns('',
@@ -217,7 +226,7 @@ views.
behavior they wish, as long as the method returns a redirect-ready URL
string.
- .. note::
+ .. note::
Documentation on class-based views is a work in progress. As yet, only the
methods defined directly on the class are documented here, not methods
diff --git a/docs/ref/class-based-views/flattened-index.txt b/docs/ref/class-based-views/flattened-index.txt
new file mode 100644
index 0000000000..cbce3690e2
--- /dev/null
+++ b/docs/ref/class-based-views/flattened-index.txt
@@ -0,0 +1,556 @@
+===========================================
+Class-based generic views - flattened index
+===========================================
+
+This index provides an alternate organization of the reference documentation
+for class-based views. For each view, the effective attributes and methods from
+the class tree are represented under that view. For the reference
+documentation organized by the class which defines the behavior, see
+:doc:`Class-based views</ref/class-based-views/index>`
+
+Simple generic views
+--------------------
+
+View
+~~~~
+.. class:: View()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.base.View.http_method_names`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+
+TemplateView
+~~~~~~~~~~~~
+.. class:: TemplateView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.base.TemplateView.get`
+* :meth:`~django.views.generic.base.TemplateView.get_context_data`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+RedirectView
+~~~~~~~~~~~~
+.. class:: RedirectView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.base.RedirectView.permanent`
+* :attr:`~django.views.generic.base.RedirectView.query_string`
+* :attr:`~django.views.generic.base.RedirectView.url`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.RedirectView.delete`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.base.RedirectView.get`
+* :meth:`~django.views.generic.base.RedirectView.get_redirect_url`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.base.RedirectView.options`
+* :meth:`~django.views.generic.base.RedirectView.post`
+* :meth:`~django.views.generic.base.RedirectView.put`
+
+Detail Views
+------------
+
+DetailView
+~~~~~~~~~~
+.. class:: DetailView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.detail.BaseDetailView.get`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+List Views
+----------
+
+ListView
+~~~~~~~~
+.. class:: ListView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.list.BaseListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+Editing views
+-------------
+
+FormView
+~~~~~~~~
+.. class:: FormView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
+* :meth:`~django.views.generic.edit.FormMixin.form_valid`
+* :meth:`~django.views.generic.edit.ProcessFormView.get`
+* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
+* :meth:`~django.views.generic.edit.FormMixin.get_form`
+* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.edit.ProcessFormView.post`
+* :meth:`~django.views.generic.edit.ProcessFormView.put`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+CreateView
+~~~~~~~~~~
+.. class:: CreateView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
+* :meth:`~django.views.generic.edit.FormMixin.form_valid`
+* :meth:`~django.views.generic.edit.ProcessFormView.get`
+* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
+* :meth:`~django.views.generic.edit.FormMixin.get_form`
+* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.edit.ProcessFormView.post`
+* :meth:`~django.views.generic.edit.ProcessFormView.put`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+UpdateView
+~~~~~~~~~~
+.. class:: UpdateView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
+* :meth:`~django.views.generic.edit.FormMixin.form_valid`
+* :meth:`~django.views.generic.edit.ProcessFormView.get`
+* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
+* :meth:`~django.views.generic.edit.FormMixin.get_form`
+* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.edit.ProcessFormView.post`
+* :meth:`~django.views.generic.edit.ProcessFormView.put`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+DeleteView
+~~~~~~~~~~
+.. class:: DeleteView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.edit.DeletionMixin.success_url` [:meth:`~django.views.generic.edit.DeletionMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.edit.DeletionMixin.delete`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.detail.BaseDetailView.get`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.edit.DeletionMixin.post`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+Date-based views
+----------------
+
+ArchiveIndexView
+~~~~~~~~~~~~~~~~
+.. class:: ArchiveIndexView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+YearArchiveView
+~~~~~~~~~~~~~~~
+.. class:: YearArchiveView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.dates.BaseYearArchiveView.make_object_list` [:meth:`~django.views.generic.dates.BaseYearArchiveView.get_make_object_list`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+MonthArchiveView
+~~~~~~~~~~~~~~~~
+.. class:: MonthArchiveView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
+* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+WeekArchiveView
+~~~~~~~~~~~~~~~
+.. class:: WeekArchiveView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.WeekMixin.week` [:meth:`~django.views.generic.dates.WeekMixin.get_week`]
+* :attr:`~django.views.generic.dates.WeekMixin.week_format` [:meth:`~django.views.generic.dates.WeekMixin.get_week_format`]
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+DayArchiveView
+~~~~~~~~~~~~~~
+.. class:: DayArchiveView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
+* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
+* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+TodayArchiveView
+~~~~~~~~~~~~~~~~
+.. class:: TodayArchiveView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
+* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
+* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
+* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
+* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
+* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.dates.BaseDateListView.get`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
+* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
+* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
+* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
+
+DateDetailView
+~~~~~~~~~~~~~~
+.. class:: DateDetailView()
+
+**Attributes** (with optional accessor):
+
+* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
+* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
+* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
+* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
+* :attr:`~django.views.generic.base.View.http_method_names`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
+* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
+* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
+* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
+* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
+* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
+* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
+
+**Methods**
+
+* :meth:`~django.views.generic.base.View.as_view`
+* :meth:`~django.views.generic.base.View.dispatch`
+* :meth:`~django.views.generic.detail.BaseDetailView.get`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
+* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
+* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
+* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
+* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
+* :meth:`~django.views.generic.base.View.head`
+* :meth:`~django.views.generic.base.View.http_method_not_allowed`
+* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt
index 69a98df77b..12776cbb94 100644
--- a/docs/ref/class-based-views/generic-date-based.txt
+++ b/docs/ref/class-based-views/generic-date-based.txt
@@ -5,6 +5,9 @@ Generic date views
Date-based generic views (in the module :mod:`django.views.generic.dates`)
are views for displaying drilldown pages for date-based data.
+ArchiveIndexView
+----------------
+
.. class:: django.views.generic.dates.ArchiveIndexView
A top-level index page showing the "latest" objects, by date. Objects with
@@ -21,11 +24,17 @@ are views for displaying drilldown pages for date-based data.
* :class:`django.views.generic.list.MultipleObjectMixin`
* :class:`django.views.generic.dates.DateMixin`
* :class:`django.views.generic.base.View`
-
+
**Notes**
* Uses a default ``context_object_name`` of ``latest``.
* Uses a default ``template_name_suffix`` of ``_archive``.
+ * Defaults to providing ``date_list`` by year, but this can be altered to
+ month or day using the attribute ``date_list_period``. This also applies
+ to all subclass views.
+
+YearArchiveView
+---------------
.. class:: django.views.generic.dates.YearArchiveView
@@ -86,6 +95,9 @@ are views for displaying drilldown pages for date-based data.
* Uses a default ``template_name_suffix`` of ``_archive_year``.
+MonthArchiveView
+----------------
+
.. class:: django.views.generic.dates.MonthArchiveView
A monthly archive page showing all objects in a given month. Objects with a
@@ -134,6 +146,9 @@ are views for displaying drilldown pages for date-based data.
* Uses a default ``template_name_suffix`` of ``_archive_month``.
+WeekArchiveView
+---------------
+
.. class:: django.views.generic.dates.WeekArchiveView
A weekly archive page showing all objects in a given week. Objects with a
@@ -175,6 +190,9 @@ are views for displaying drilldown pages for date-based data.
* Uses a default ``template_name_suffix`` of ``_archive_week``.
+DayArchiveView
+--------------
+
.. class:: django.views.generic.dates.DayArchiveView
A day archive page showing all objects in a given day. Days in the future
@@ -225,6 +243,9 @@ are views for displaying drilldown pages for date-based data.
* Uses a default ``template_name_suffix`` of ``_archive_day``.
+TodayArchiveView
+----------------
+
.. class:: django.views.generic.dates.TodayArchiveView
A day archive page showing all objects for *today*. This is exactly the
@@ -246,6 +267,10 @@ are views for displaying drilldown pages for date-based data.
* :class:`django.views.generic.dates.DateMixin`
* :class:`django.views.generic.base.View`
+
+DateDetailView
+--------------
+
.. class:: django.views.generic.dates.DateDetailView
A page representing an individual object. If the object has a date value in
diff --git a/docs/ref/class-based-views/generic-display.txt b/docs/ref/class-based-views/generic-display.txt
index bbf0d4f05a..ef3bc179ee 100644
--- a/docs/ref/class-based-views/generic-display.txt
+++ b/docs/ref/class-based-views/generic-display.txt
@@ -5,6 +5,9 @@ Generic display views
The two following generic class-based views are designed to display data. On
many projects they are typically the most commonly used views.
+DetailView
+----------
+
.. class:: django.views.generic.detail.DetailView
While this view is executing, ``self.object`` will contain the object that
@@ -39,7 +42,7 @@ many projects they are typically the most commonly used views.
from articles.models import Article
class ArticleDetailView(DetailView):
-
+
model = Article
def get_context_data(self, **kwargs):
@@ -55,7 +58,10 @@ many projects they are typically the most commonly used views.
urlpatterns = patterns('',
url(r'^(?P<slug>[-_\w]+)/$', ArticleDetailView.as_view(), name='article-detail'),
- )
+ )
+
+ListView
+--------
.. class:: django.views.generic.list.ListView
diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt
index a65a59bc8b..2fac06ee02 100644
--- a/docs/ref/class-based-views/generic-editing.txt
+++ b/docs/ref/class-based-views/generic-editing.txt
@@ -2,7 +2,7 @@
Generic editing views
=====================
-The following views are described on this page and provide a foundation for
+The following views are described on this page and provide a foundation for
editing content:
* :class:`django.views.generic.edit.FormView`
@@ -13,7 +13,7 @@ editing content:
.. note::
Some of the examples on this page assume that a model titled 'Author'
- has been defined. For these cases we assume the following has been defined
+ has been defined. For these cases we assume the following has been defined
in `myapp/models.py`::
from django import models
@@ -25,6 +25,9 @@ editing content:
def get_absolute_url(self):
return reverse('author-detail', kwargs={'pk': self.pk})
+FormView
+--------
+
.. class:: django.views.generic.edit.FormView
A view that displays a form. On error, redisplays the form with validation
@@ -69,6 +72,8 @@ editing content:
form.send_email()
return super(ContactView, self).form_valid(form)
+CreateView
+----------
.. class:: django.views.generic.edit.CreateView
@@ -94,7 +99,7 @@ editing content:
.. attribute:: template_name_suffix
The CreateView page displayed to a GET request uses a
- ``template_name_suffix`` of ``'_form.html'``. For
+ ``template_name_suffix`` of ``'_form.html'``. For
example, changing this attribute to ``'_create_form.html'`` for a view
creating objects for the the example `Author` model would cause the the
default `template_name` to be ``'myapp/author_create_form.html'``.
@@ -107,6 +112,9 @@ editing content:
class AuthorCreate(CreateView):
model = Author
+UpdateView
+----------
+
.. class:: django.views.generic.edit.UpdateView
A view that displays a form for editing an existing object, redisplaying
@@ -133,10 +141,10 @@ editing content:
.. attribute:: template_name_suffix
The UpdateView page displayed to a GET request uses a
- ``template_name_suffix`` of ``'_form.html'``. For
+ ``template_name_suffix`` of ``'_form.html'``. For
example, changing this attribute to ``'_update_form.html'`` for a view
updating objects for the the example `Author` model would cause the the
- default `template_name` to be ``'myapp/author_update_form.html'``.
+ default `template_name` to be ``'myapp/author_update_form.html'``.
**Example views.py**::
@@ -146,6 +154,9 @@ editing content:
class AuthorUpdate(UpdateView):
model = Author
+DeleteView
+----------
+
.. class:: django.views.generic.edit.DeleteView
A view that displays a confirmation page and deletes an existing object.
@@ -171,10 +182,10 @@ editing content:
.. attribute:: template_name_suffix
The DeleteView page displayed to a GET request uses a
- ``template_name_suffix`` of ``'_confirm_delete.html'``. For
+ ``template_name_suffix`` of ``'_confirm_delete.html'``. For
example, changing this attribute to ``'_check_delete.html'`` for a view
deleting objects for the the example `Author` model would cause the the
- default `template_name` to be ``'myapp/author_check_delete.html'``.
+ default `template_name` to be ``'myapp/author_check_delete.html'``.
**Example views.py**::
@@ -185,4 +196,4 @@ editing content:
class AuthorDelete(DeleteView):
model = Author
- success_url = reverse_lazy('author-list')
+ success_url = reverse_lazy('author-list')
diff --git a/docs/ref/class-based-views/index.txt b/docs/ref/class-based-views/index.txt
index f2271d2506..f0e7bbc6c1 100644
--- a/docs/ref/class-based-views/index.txt
+++ b/docs/ref/class-based-views/index.txt
@@ -6,13 +6,14 @@ Class-based views API reference. For introductory material, see
:doc:`/topics/class-based-views/index`.
.. toctree::
- :maxdepth: 1
+ :maxdepth: 3
base
generic-display
generic-editing
generic-date-based
mixins
+ flattened-index
Specification
-------------
diff --git a/docs/ref/class-based-views/mixins-date-based.txt b/docs/ref/class-based-views/mixins-date-based.txt
index a65471e68d..6bf6f10b5d 100644
--- a/docs/ref/class-based-views/mixins-date-based.txt
+++ b/docs/ref/class-based-views/mixins-date-based.txt
@@ -3,6 +3,9 @@ Date-based mixins
=================
+YearMixin
+---------
+
.. class:: django.views.generic.dates.YearMixin
A mixin that can be used to retrieve and provide parsing information for a
@@ -36,6 +39,9 @@ Date-based mixins
Raises a 404 if no valid year specification can be found.
+MonthMixin
+----------
+
.. class:: django.views.generic.dates.MonthMixin
A mixin that can be used to retrieve and provide parsing information for a
@@ -82,6 +88,9 @@ Date-based mixins
date provided. If ``allow_empty = False``, returns the previous month
that contained data.
+DayMixin
+--------
+
.. class:: django.views.generic.dates.DayMixin
A mixin that can be used to retrieve and provide parsing information for a
@@ -127,6 +136,9 @@ Date-based mixins
Returns a date object containing the previous day. If
``allow_empty = False``, returns the previous day that contained data.
+WeekMixin
+---------
+
.. class:: django.views.generic.dates.WeekMixin
A mixin that can be used to retrieve and provide parsing information for a
@@ -161,6 +173,9 @@ Date-based mixins
Raises a 404 if no valid week specification can be found.
+DateMixin
+---------
+
.. class:: django.views.generic.dates.DateMixin
A mixin class providing common behavior for all date-based views.
@@ -204,6 +219,9 @@ Date-based mixins
is greater than the current date/time. Returns
:attr:`DateMixin.allow_future` by default.
+BaseDateListView
+----------------
+
.. class:: django.views.generic.dates.BaseDateListView
A base class that provides common behavior for all date-based views. There
diff --git a/docs/ref/class-based-views/mixins-editing.txt b/docs/ref/class-based-views/mixins-editing.txt
index 89610889db..95dd24f442 100644
--- a/docs/ref/class-based-views/mixins-editing.txt
+++ b/docs/ref/class-based-views/mixins-editing.txt
@@ -14,6 +14,9 @@ The following mixins are used to construct Django's editing views:
Examples of how these are combined into editing views can be found at
the documentation on ``Generic editing views``.
+FormMixin
+---------
+
.. class:: django.views.generic.edit.FormMixin
A mixin class that provides facilities for creating and displaying forms.
@@ -90,6 +93,9 @@ The following mixins are used to construct Django's editing views:
:meth:`~django.views.generic.FormMixin.form_invalid`.
+ModelFormMixin
+--------------
+
.. class:: django.views.generic.edit.ModelFormMixin
A form mixin that works on ModelForms, rather than a standalone form.
@@ -147,12 +153,16 @@ The following mixins are used to construct Django's editing views:
.. method:: form_invalid()
Renders a response, providing the invalid form as context.
-
+
+
+ProcessFormView
+---------------
+
.. class:: django.views.generic.edit.ProcessFormView
A mixin that provides basic HTTP GET and POST workflow.
- .. note::
+ .. note::
This is named 'ProcessFormView' and inherits directly from
:class:`django.views.generic.base.View`, but breaks if used
diff --git a/docs/ref/class-based-views/mixins-multiple-object.txt b/docs/ref/class-based-views/mixins-multiple-object.txt
index b414355c6b..8bc613b887 100644
--- a/docs/ref/class-based-views/mixins-multiple-object.txt
+++ b/docs/ref/class-based-views/mixins-multiple-object.txt
@@ -2,6 +2,9 @@
Multiple object mixins
======================
+MultipleObjectMixin
+-------------------
+
.. class:: django.views.generic.list.MultipleObjectMixin
A mixin that can be used to display a list of objects.
@@ -148,6 +151,9 @@ Multiple object mixins
this context variable will be ``None``.
+MultipleObjectTemplateResponseMixin
+-----------------------------------
+
.. class:: django.views.generic.list.MultipleObjectTemplateResponseMixin
A mixin class that performs template-based response rendering for views
diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt
index 33d0db3134..61fc945cd3 100644
--- a/docs/ref/class-based-views/mixins-simple.txt
+++ b/docs/ref/class-based-views/mixins-simple.txt
@@ -2,6 +2,9 @@
Simple mixins
=============
+ContextMixin
+------------
+
.. class:: django.views.generic.base.ContextMixin
.. versionadded:: 1.5
@@ -14,8 +17,23 @@ Simple mixins
.. method:: get_context_data(**kwargs)
- Returns a dictionary representing the template context. The
- keyword arguments provided will make up the returned context.
+ Returns a dictionary representing the template context. The keyword
+ arguments provided will make up the returned context.
+
+ The template context of all class-based generic views include a
+ ``view`` variable that points to the ``View`` instance.
+
+ .. admonition:: Use ``alters_data`` where appropriate
+
+ Note that having the view instance in the template context may
+ expose potentially hazardous methods to template authors. To
+ prevent methods like this from being called in the template, set
+ ``alters_data=True`` on those methods. For more information, read
+ the documentation on :ref:`rendering a template context
+ <alters-data-description>`.
+
+TemplateResponseMixin
+---------------------
.. class:: django.views.generic.base.TemplateResponseMixin
diff --git a/docs/ref/class-based-views/mixins-single-object.txt b/docs/ref/class-based-views/mixins-single-object.txt
index a31608dbd4..77f52b96c6 100644
--- a/docs/ref/class-based-views/mixins-single-object.txt
+++ b/docs/ref/class-based-views/mixins-single-object.txt
@@ -2,6 +2,9 @@
Single object mixins
====================
+SingleObjectMixin
+-----------------
+
.. class:: django.views.generic.detail.SingleObjectMixin
Provides a mechanism for looking up an object associated with the
@@ -86,6 +89,9 @@ Single object mixins
``context_object_name`` is specified, that variable will also be
set in the context, with the same value as ``object``.
+SingleObjectTemplateResponseMixin
+---------------------------------
+
.. class:: django.views.generic.detail.SingleObjectTemplateResponseMixin
A mixin class that performs template-based response rendering for views
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index 4d39981a4d..66a5a2cc4f 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -561,8 +561,6 @@ subclass::
.. attribute:: ModelAdmin.list_filter
- .. versionchanged:: 1.4
-
Set ``list_filter`` to activate filters in the right sidebar of the change
list page of the admin, as illustrated in the following screenshot:
@@ -586,6 +584,8 @@ subclass::
class PersonAdmin(UserAdmin):
list_filter = ('company__name',)
+ .. versionadded:: 1.4
+
* a class inheriting from :mod:`django.contrib.admin.SimpleListFilter`,
which you need to provide the ``title`` and ``parameter_name``
attributes to and override the ``lookups`` and ``queryset`` methods,
@@ -623,7 +623,7 @@ subclass::
provided in the query string and retrievable via
`self.value()`.
"""
- # Compare the requested value (either '80s' or 'other')
+ # Compare the requested value (either '80s' or '90s')
# to decide how to filter the queryset.
if self.value() == '80s':
return queryset.filter(birthday__gte=date(1980, 1, 1),
@@ -671,6 +671,8 @@ subclass::
birthday__lte=date(1999, 12, 31)).exists():
yield ('90s', _('in the nineties'))
+ .. versionadded:: 1.4
+
* a tuple, where the first element is a field name and the second
element is a class inheriting from
:mod:`django.contrib.admin.FieldListFilter`, for example::
diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt
index af937e036e..4b1dd96280 100644
--- a/docs/ref/contrib/comments/index.txt
+++ b/docs/ref/contrib/comments/index.txt
@@ -158,11 +158,13 @@ For example::
.. warning::
- There's a known bug in Safari/Webkit which causes the named anchor to be
+ There's a `known bug`_ in Safari/Webkit which causes the named anchor to be
forgotten following a redirect. The practical impact for comments is that
the Safari/webkit browsers will arrive at the correct page but will not
scroll to the named anchor.
+.. _`known bug`: https://bugs.webkit.org/show_bug.cgi?id=24175
+
.. templatetag:: get_comment_count
Counting comments
diff --git a/docs/ref/contrib/csrf.txt b/docs/ref/contrib/csrf.txt
index f25cb31e4b..8d352ff8b2 100644
--- a/docs/ref/contrib/csrf.txt
+++ b/docs/ref/contrib/csrf.txt
@@ -84,47 +84,94 @@ AJAX
While the above method can be used for AJAX POST requests, it has some
inconveniences: you have to remember to pass the CSRF token in as POST data with
every POST request. For this reason, there is an alternative method: on each
-XMLHttpRequest, set a custom `X-CSRFToken` header to the value of the CSRF
+XMLHttpRequest, set a custom ``X-CSRFToken`` header to the value of the CSRF
token. This is often easier, because many javascript frameworks provide hooks
-that allow headers to be set on every request. In jQuery, you can use the
-``ajaxSend`` event as follows:
+that allow headers to be set on every request.
+
+As a first step, you must get the CSRF token itself. The recommended source for
+the token is the ``csrftoken`` cookie, which will be set if you've enabled CSRF
+protection for your views as outlined above.
+
+.. note::
+
+ The CSRF token cookie is named ``csrftoken`` by default, but you can control
+ the cookie name via the :setting:`CSRF_COOKIE_NAME` setting.
+
+Acquiring the token is straightforward:
.. code-block:: javascript
- jQuery(document).ajaxSend(function(event, xhr, settings) {
- function getCookie(name) {
- var cookieValue = null;
- if (document.cookie && document.cookie != '') {
- var cookies = document.cookie.split(';');
- for (var i = 0; i < cookies.length; i++) {
- var cookie = jQuery.trim(cookies[i]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
+ // using jQuery
+ function getCookie(name) {
+ var cookieValue = null;
+ if (document.cookie && document.cookie != '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
}
}
- return cookieValue;
- }
- function sameOrigin(url) {
- // url could be relative or scheme relative or absolute
- var host = document.location.host; // host + port
- var protocol = document.location.protocol;
- var sr_origin = '//' + host;
- var origin = protocol + sr_origin;
- // Allow absolute or scheme relative URLs to same origin
- return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
- (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
- // or any other URL that isn't scheme relative or absolute i.e relative.
- !(/^(\/\/|http:|https:).*/.test(url));
- }
- function safeMethod(method) {
- return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
+ return cookieValue;
+ }
+ 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``:
+
+.. code-block:: javascript
+
+ var csrftoken = $.cookie('csrftoken');
+
+.. note::
+
+ The CSRF token is also present in the DOM, but only if explicitly included
+ using :ttag:`csrf_token` in a template. The cookie contains the canonical
+ token; the ``CsrfViewMiddleware`` will prefer the cookie to the token in
+ the DOM. Regardless, you're guaranteed to have the cookie if the token is
+ present in the DOM, so you should use the cookie!
- if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
- xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
+.. warning::
+
+ If your view is not rendering a template containing the :ttag:`csrf_token`
+ template tag, Django might not set the CSRF token cookie. This is common in
+ cases where forms are dynamically added to the page. To address this case,
+ Django provides a view decorator which forces setting of the cookie:
+ :func:`~django.views.decorators.csrf.ensure_csrf_cookie`.
+
+Finally, you'll have to actually set the header on your AJAX request, while
+protecting the CSRF token from being sent to other domains.
+
+.. code-block:: javascript
+
+ function csrfSafeMethod(method) {
+ // these HTTP methods do not require CSRF protection
+ return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+ }
+ function sameOrigin(url) {
+ // test that a given url is a same-origin URL
+ // url could be relative or scheme relative or absolute
+ var host = document.location.host; // host + port
+ var protocol = document.location.protocol;
+ var sr_origin = '//' + host;
+ var origin = protocol + sr_origin;
+ // Allow absolute or scheme relative URLs to same origin
+ return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
+ (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
+ // or any other URL that isn't scheme relative or absolute i.e relative.
+ !(/^(\/\/|http:|https:).*/.test(url));
+ }
+ $.ajaxSetup({
+ beforeSend: function(xhr, settings) {
+ if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
+ // Send the token to same-origin, relative URLs only.
+ // Send the token only if the method warrants CSRF protection
+ // Using the CSRFToken value acquired earlier
+ xhr.setRequestHeader("X-CSRFToken", csrftoken);
+ }
}
});
@@ -133,18 +180,32 @@ that allow headers to be set on every request. In jQuery, you can use the
Due to a bug introduced in jQuery 1.5, the example above will not work
correctly on that version. Make sure you are running at least jQuery 1.5.1.
-Adding this to a javascript file that is included on your site will ensure that
-AJAX POST requests that are made via jQuery will not be caught by the CSRF
-protection.
+You can use `settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in
+jQuery 1.5 and newer in order to replace the `sameOrigin` logic above:
-The above code could be simplified by using the `jQuery cookie plugin
-<http://plugins.jquery.com/project/Cookie>`_ to replace ``getCookie``, and
-`settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in jQuery 1.5 and
-later to replace ``sameOrigin``.
+.. code-block:: javascript
+
+ function csrfSafeMethod(method) {
+ // these HTTP methods do not require CSRF protection
+ return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+ }
+ $.ajaxSetup({
+ crossDomain: false, // obviates need for sameOrigin test
+ beforeSend: function(xhr, settings) {
+ if (!csrfSafeMethod(settings.type)) {
+ xhr.setRequestHeader("X-CSRFToken", csrftoken);
+ }
+ }
+ });
+
+.. note::
+
+ In a `security release blogpost`_, a simpler "same origin test" example
+ was provided which only checked for a relative URL. The ``sameOrigin``
+ test above supersedes that example—it works for edge cases like
+ scheme-relative or absolute URLs for the same domain.
-In addition, if the CSRF cookie has not been sent to the client by use of
-:ttag:`csrf_token`, you may need to ensure the client receives the cookie by
-using :func:`~django.views.decorators.csrf.ensure_csrf_cookie`.
+.. _security release blogpost: https://www.djangoproject.com/weblog/2011/feb/08/security/
Other template engines
----------------------
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index 6b5773b5a4..3de449708f 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -42,6 +42,16 @@ To install the flatpages app, follow these steps:
2. Add ``'django.contrib.flatpages'`` to your :setting:`INSTALLED_APPS`
setting.
+Then either:
+
+3. Add an entry in your URLconf. For example::
+
+ urlpatterns = patterns('',
+ ('^pages/', include('django.contrib.flatpages.urls')),
+ )
+
+or:
+
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
to your :setting:`MIDDLEWARE_CLASSES` setting.
@@ -57,8 +67,38 @@ and ``django_flatpage_sites``. ``django_flatpage`` is a simple lookup table
that simply maps a URL to a title and bunch of text content.
``django_flatpage_sites`` associates a flatpage with a site.
+Using the URLconf
+-----------------
+
+There are several ways to include the flat pages in your URLconf. You can
+dedicate a particular path to flat pages::
+
+ urlpatterns = patterns('',
+ ('^pages/', include('django.contrib.flatpages.urls')),
+ )
+
+You can also set it up as a "catchall" pattern. In this case, it is important
+to place the pattern at the end of the other urlpatterns::
+
+ # Your other patterns here
+ urlpatterns += patterns('django.contrib.flatpages.views',
+ (r'^(?P<url>.*)$', 'flatpage'),
+ )
+
+Another common setup is to use flat pages for a limited set of known pages and
+to hard code the urls, so you can reference them with the :ttag:`url` template
+tag::
+
+ urlpatterns += patterns('django.contrib.flatpages.views',
+ url(r'^about-us/$', 'flatpage', {'url': '/about-us/'}, name='about'),
+ url(r'^license/$', 'flatpage', {'url': '/license/'}, name='license'),
+ )
+
+Using the middleware
+--------------------
+
The :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
-does all of the work.
+can do all of the work.
.. class:: FlatpageFallbackMiddleware
@@ -255,4 +295,3 @@ For example:
{% get_flatpages '/about/' as about_pages %}
{% get_flatpages about_prefix as about_pages %}
{% get_flatpages '/about/' for someuser as about_pages %}
-
diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt
index 7d229a5d66..b8e585a4d2 100644
--- a/docs/ref/contrib/formtools/form-wizard.txt
+++ b/docs/ref/contrib/formtools/form-wizard.txt
@@ -86,8 +86,8 @@ the message itself. Here's what the :file:`forms.py` might look like::
section :ref:`Handling files <wizard-files>` below to learn more about
what to do.
-Creating a ``WizardView`` class
--------------------------------
+Creating a ``WizardView`` subclass
+----------------------------------
The next step is to create a
:class:`django.contrib.formtools.wizard.views.WizardView` subclass. You can
@@ -528,7 +528,7 @@ We define our wizard in a ``views.py``::
We need to add the ``ContactWizard`` to our ``urls.py`` file::
- from django.conf.urls import pattern
+ from django.conf.urls import patterns
from myapp.forms import ContactForm1, ContactForm2
from myapp.views import ContactWizard, show_message_form_condition
diff --git a/docs/ref/contrib/gis/install.txt b/docs/ref/contrib/gis/install.txt
index 72bd72a6f8..3e952c173b 100644
--- a/docs/ref/contrib/gis/install.txt
+++ b/docs/ref/contrib/gis/install.txt
@@ -60,14 +60,14 @@ The geospatial libraries required for a GeoDjango installation depends
on the spatial database used. The following lists the library requirements,
supported versions, and any notes for each of the supported database backends:
-================== ============================== ================== ==========================================================
+================== ============================== ================== =========================================
Database Library Requirements Supported Versions Notes
-================== ============================== ================== ==========================================================
+================== ============================== ================== =========================================
PostgreSQL GEOS, PROJ.4, PostGIS 8.1+ Requires PostGIS.
MySQL GEOS 5.x Not OGC-compliant; limited functionality.
Oracle GEOS 10.2, 11 XE not supported; not tested with 9.
-SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 2.3+, pysqlite2 2.5+, and Django 1.1.
-================== ============================== ================== ==========================================================
+SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 2.3+, pysqlite2 2.5+
+================== ============================== ================== =========================================
.. _geospatial_libs:
@@ -140,7 +140,7 @@ internal geometry representation used by GeoDjango (it's behind the "lazy"
geometries). Specifically, the C API library is called (e.g., ``libgeos_c.so``)
directly from Python using ctypes.
-First, download GEOS 3.2 from the refractions Web site and untar the source
+First, download GEOS 3.3.0 from the refractions Web site and untar the source
archive::
$ wget http://download.osgeo.org/geos/geos-3.3.0.tar.bz2
@@ -421,7 +421,7 @@ After SQLite has been built with the R*Tree module enabled, get the latest
SpatiaLite library source and tools bundle from the `download page`__::
$ wget http://www.gaia-gis.it/gaia-sins/libspatialite-sources/libspatialite-amalgamation-2.3.1.tar.gz
- $ wget http://www.gaia-gis.it/gaia-sins/libspatialite-sources/spatialite-tools-2.3.1.tar.gz
+ $ wget http://www.gaia-gis.it/gaia-sins/spatialite-tools-sources/spatialite-tools-2.3.1.tar.gz
$ tar xzf libspatialite-amalgamation-2.3.1.tar.gz
$ tar xzf spatialite-tools-2.3.1.tar.gz
@@ -467,8 +467,8 @@ pysqlite2
^^^^^^^^^
Because SpatiaLite must be loaded as an external extension, it requires the
-``enable_load_extension`` method, which is only available in versions 2.5+.
-Thus, download pysqlite2 2.6, and untar::
+``enable_load_extension`` method, which is only available in versions 2.5+ of
+pysqlite2. Thus, download pysqlite2 2.6, and untar::
$ wget http://pysqlite.googlecode.com/files/pysqlite-2.6.0.tar.gz
$ tar xzf pysqlite-2.6.0.tar.gz
@@ -582,8 +582,8 @@ Creating a spatial database for SpatiaLite
After you've installed SpatiaLite, you'll need to create a number of spatial
metadata tables in your database in order to perform spatial queries.
-If you're using SpatiaLite 3.0 or newer, use the ``spatialite`` utility to
-call the ``InitSpatiaMetaData()`` function, like this::
+If you're using SpatiaLite 2.4 or newer, use the ``spatialite`` utility to
+call the ``InitSpatialMetaData()`` function, like this::
$ spatialite geodjango.db "SELECT InitSpatialMetaData();"
the SPATIAL_REF_SYS table already contains some row(s)
@@ -593,19 +593,17 @@ call the ``InitSpatiaMetaData()`` function, like this::
You can safely ignore the error messages shown. When you've done this, you can
skip the rest of this section.
-If you're using a version of SpatiaLite older than 3.0, you'll need to download
-a database-initialization file and execute its SQL queries in your database.
+If you're using SpatiaLite 2.3, you'll need to download a
+database-initialization file and execute its SQL queries in your database.
-First, get it from the appropriate SpatiaLite Resources page (
-http://www.gaia-gis.it/spatialite-2.3.1/resources.html for 2.3 or
-http://www.gaia-gis.it/spatialite-2.4.0/ for 2.4)::
+First, get it from the `SpatiaLite Resources`__ page::
$ wget http://www.gaia-gis.it/spatialite-2.3.1/init_spatialite-2.3.sql.gz
$ gunzip init_spatialite-2.3.sql.gz
Then, use the ``spatialite`` command to initialize a spatial database::
- $ spatialite geodjango.db < init_spatialite-2.X.sql
+ $ spatialite geodjango.db < init_spatialite-2.3.sql
.. note::
@@ -613,6 +611,8 @@ Then, use the ``spatialite`` command to initialize a spatial database::
you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key
inside your ``settings.py``.
+__ http://www.gaia-gis.it/spatialite-2.3.1/resources.html
+
Add ``django.contrib.gis`` to :setting:`INSTALLED_APPS`
-------------------------------------------------------
@@ -643,10 +643,6 @@ Invoke the Django shell from your project and execute the
>>> from django.contrib.gis.utils import add_srs_entry
>>> add_srs_entry(900913)
-.. note::
-
- In Django 1.1 the name of this function is ``add_postgis_srs``.
-
This adds an entry for the 900913 SRID to the ``spatial_ref_sys`` (or equivalent)
table, making it possible for the spatial database to transform coordinates in
this projection. You only need to execute this command *once* per spatial database.
@@ -824,8 +820,10 @@ Download the framework packages for:
* GDAL
Install the packages in the order they are listed above, as the GDAL and SQLite
-packages require the packages listed before them. Afterwards, you can also
-install the KyngChaos binary packages for `PostgreSQL and PostGIS`__.
+packages require the packages listed before them.
+
+Afterwards, you can also install the KyngChaos binary packages for `PostgreSQL
+and PostGIS`__.
After installing the binary packages, you'll want to add the following to
your ``.profile`` to be able to run the package programs from the command-line::
diff --git a/docs/ref/contrib/gis/testing.txt b/docs/ref/contrib/gis/testing.txt
index 78663b967c..d12c884a1b 100644
--- a/docs/ref/contrib/gis/testing.txt
+++ b/docs/ref/contrib/gis/testing.txt
@@ -119,9 +119,10 @@ Settings
``SPATIALITE_SQL``
^^^^^^^^^^^^^^^^^^
-Only relevant when using a SpatiaLite version older than 3.0.
+Only relevant when using a SpatiaLite version 2.3.
-By default, the GeoDjango test runner looks for the SpatiaLite SQL in the
+By default, the GeoDjango test runner looks for the :ref:`file containing the
+SpatiaLite dababase-initialization SQL code <create_spatialite_db>` in the
same directory where it was invoked (by default the same directory where
``manage.py`` is located). To use a different location, add the following to
your settings::
diff --git a/docs/ref/contrib/gis/tutorial.txt b/docs/ref/contrib/gis/tutorial.txt
index 3a63493137..15863aee7b 100644
--- a/docs/ref/contrib/gis/tutorial.txt
+++ b/docs/ref/contrib/gis/tutorial.txt
@@ -671,6 +671,17 @@ of abstraction::
__ http://spatialreference.org/ref/epsg/32140/
+.. admonition:: Raw queries
+
+ When using :doc:`raw queries </topics/db/sql>`, you should generally wrap
+ your geometry fields with the ``asText()`` SQL function so as the field
+ value will be recognized by GEOS::
+
+ City.objects.raw('SELECT id, name, asText(point) from myapp_city')
+
+ This is not absolutely required by PostGIS, but generally you should only
+ use raw queries when you know exactly what you are doing.
+
Lazy Geometries
---------------
Geometries come to GeoDjango in a standardized textual representation. Upon
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index 92b5665bea..3e256e9d9e 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -56,10 +56,10 @@ will do some additional queries to set these parameters.
Transaction handling
---------------------
-:doc:`By default </topics/db/transactions>`, Django starts a transaction when a
-database connection is first used and commits the result at the end of the
-request/response handling. The PostgreSQL backends normally operate the same
-as any other Django backend in this respect.
+:doc:`By default </topics/db/transactions>`, Django runs with an open
+transaction which it commits automatically when any built-in, data-altering
+model function is called. The PostgreSQL backends normally operate the same as
+any other Django backend in this respect.
.. _postgresql-autocommit-mode:
diff --git a/docs/ref/files/file.txt b/docs/ref/files/file.txt
index 99547f1c9e..ada614df45 100644
--- a/docs/ref/files/file.txt
+++ b/docs/ref/files/file.txt
@@ -91,14 +91,18 @@ The ``ContentFile`` Class
.. class:: ContentFile(File)
The ``ContentFile`` class inherits from :class:`~django.core.files.File`,
- but unlike :class:`~django.core.files.File` it operates on string content,
- rather than an actual file. For example::
+ but unlike :class:`~django.core.files.File` it operates on string content
+ (bytes also supported), rather than an actual file. For example::
from __future__ import unicode_literals
from django.core.files.base import ContentFile
- f1 = ContentFile(b"my string content")
- f2 = ContentFile("my unicode content encoded as UTF-8".encode('UTF-8'))
+ f1 = ContentFile("esta sentencia está en español")
+ f2 = ContentFile(b"these are bytes")
+
+ .. versionchanged:: 1.5
+
+ ContentFile also accepts Unicode strings.
.. currentmodule:: django.core.files.images
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index a43163c5e9..275c696230 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -70,8 +70,8 @@ If ``True``, the field is allowed to be blank. Default is ``False``.
Note that this is different than :attr:`~Field.null`. :attr:`~Field.null` is
purely database-related, whereas :attr:`~Field.blank` is validation-related. If
-a field has ``blank=True``, validation on Django's admin site will allow entry
-of an empty value. If a field has ``blank=False``, the field will be required.
+a field has ``blank=True``, form validation will allow entry of an empty value.
+If a field has ``blank=False``, the field will be required.
.. _field-choices:
@@ -81,14 +81,11 @@ of an empty value. 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.
+field. If this is given, the default form widget will be a select box with
+these choices instead of the standard text field.
-If this is given, Django's admin will use a select box instead of the standard
-text field and will limit choices to the choices given.
-
-A choices list is an iterable of 2-tuples; the first element in each
-tuple is the actual value to be stored, and the second element is the
-human-readable name. For example::
+The first element in each tuple is the actual value to be stored, and the
+second element is the human-readable name. For example::
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
@@ -176,7 +173,7 @@ scenes.
.. attribute:: Field.db_index
-If ``True``, djadmin:`django-admin.py sqlindexes <sqlindexes>` will output a
+If ``True``, :djadmin:`django-admin.py sqlindexes <sqlindexes>` will output a
``CREATE INDEX`` statement for this field.
``db_tablespace``
@@ -203,8 +200,8 @@ callable it will be called every time a new object is created.
.. attribute:: Field.editable
-If ``False``, the field will not be editable in the admin or via forms
-automatically generated from the model class. Default is ``True``.
+If ``False``, the field will not be displayed in the admin or any other
+:class:`~django.forms.ModelForm`. Default is ``True``.
``error_messages``
------------------
@@ -224,11 +221,11 @@ the `Field types`_ section below.
.. attribute:: Field.help_text
-Extra "help" text to be displayed under the field on the object's admin form.
-It's useful for documentation even if your object doesn't have an admin form.
+Extra "help" text to be displayed with the form widget. It's useful for
+documentation even if your field isn't used on a form.
-Note that this value is *not* HTML-escaped when it's displayed in the admin
-interface. This lets you include HTML in :attr:`~Field.help_text` if you so
+Note that this value is *not* HTML-escaped in automatically-generated
+forms. This lets you include HTML in :attr:`~Field.help_text` if you so
desire. For example::
help_text="Please use the following format: <em>YYYY-MM-DD</em>."
@@ -259,7 +256,7 @@ Only one primary key is allowed on an object.
If ``True``, this field must be unique throughout the table.
-This is enforced at the database level and at the Django admin-form level. If
+This is enforced at the database level and by model validation. If
you try to save a model with a duplicate value in a :attr:`~Field.unique`
field, a :exc:`django.db.IntegrityError` will be raised by the model's
:meth:`~django.db.models.Model.save` method.
@@ -279,7 +276,7 @@ For example, if you have a field ``title`` that has
``unique_for_date="pub_date"``, then Django wouldn't allow the entry of two
records with the same ``title`` and ``pub_date``.
-This is enforced at the Django admin-form level but not at the database level.
+This is enforced by model validation but not at the database level.
``unique_for_month``
--------------------
@@ -337,7 +334,7 @@ otherwise. See :ref:`automatic-primary-key-fields`.
A 64 bit integer, much like an :class:`IntegerField` except that it is
guaranteed to fit numbers from -9223372036854775808 to 9223372036854775807. The
-admin represents this as an ``<input type="text">`` (a single-line input).
+default form widget for this field is a :class:`~django.forms.TextInput`.
``BooleanField``
@@ -347,7 +344,8 @@ admin represents this as an ``<input type="text">`` (a single-line input).
A true/false field.
-The admin represents this as a checkbox.
+The default form widget for this field is a
+:class:`~django.forms.CheckboxInput`.
If you need to accept :attr:`~Field.null` values then use
:class:`NullBooleanField` instead.
@@ -361,7 +359,7 @@ A string field, for small- to large-sized strings.
For large amounts of text, use :class:`~django.db.models.TextField`.
-The admin represents this as an ``<input type="text">`` (a single-line input).
+The default form widget for this field is a :class:`~django.forms.TextInput`.
:class:`CharField` has one extra required argument:
@@ -414,9 +412,10 @@ optional arguments:
for creation of timestamps. Note that the current date is *always* used;
it's not just a default value that you can override.
-The admin represents this as an ``<input type="text">`` with a JavaScript
-calendar, and a shortcut for "Today". Includes an additional ``invalid_date``
-error message key.
+The default form widget for this field is a
+:class:`~django.forms.TextInput`. The admin adds a JavaScript calendar,
+and a shortcut for "Today". Includes an additional ``invalid_date`` error
+message key.
.. note::
As currently implemented, setting ``auto_now`` or ``auto_now_add`` to
@@ -431,8 +430,9 @@ error message key.
A date and time, represented in Python by a ``datetime.datetime`` instance.
Takes the same extra arguments as :class:`DateField`.
-The admin represents this as two ``<input type="text">`` fields, with
-JavaScript shortcuts.
+The default form widget for this field is a single
+:class:`~django.forms.TextInput`. The admin uses two separate
+:class:`~django.forms.TextInput` widgets with JavaScript shortcuts.
``DecimalField``
----------------
@@ -461,7 +461,7 @@ decimal places::
models.DecimalField(..., max_digits=19, decimal_places=10)
-The admin represents this as an ``<input type="text">`` (a single-line input).
+The default form widget for this field is a :class:`~django.forms.TextInput`.
.. note::
@@ -539,8 +539,8 @@ Also has one optional argument:
Optional. A storage object, which handles the storage and retrieval of your
files. See :doc:`/topics/files` for details on how to provide this object.
-The admin represents this field as an ``<input type="file">`` (a file-upload
-widget).
+The default form widget for this field is a
+:class:`~django.forms.widgets.FileInput`.
Using a :class:`FileField` or an :class:`ImageField` (see below) in a model
takes a few steps:
@@ -725,7 +725,7 @@ can change the maximum length using the :attr:`~CharField.max_length` argument.
A floating-point number represented in Python by a ``float`` instance.
-The admin represents this as an ``<input type="text">`` (a single-line input).
+The default form widget for this field is a :class:`~django.forms.TextInput`.
.. _floatfield_vs_decimalfield:
@@ -776,16 +776,16 @@ length using the :attr:`~CharField.max_length` argument.
.. class:: IntegerField([**options])
-An integer. The admin represents this as an ``<input type="text">`` (a
-single-line input).
+An integer. The default form widget for this field is a
+:class:`~django.forms.TextInput`.
``IPAddressField``
------------------
.. class:: IPAddressField([**options])
-An IP address, in string format (e.g. "192.0.2.30"). The admin represents this
-as an ``<input type="text">`` (a single-line input).
+An IP address, in string format (e.g. "192.0.2.30"). The default form widget
+for this field is a :class:`~django.forms.TextInput`.
``GenericIPAddressField``
-------------------------
@@ -795,8 +795,8 @@ as an ``<input type="text">`` (a single-line input).
.. versionadded:: 1.4
An IPv4 or IPv6 address, in string format (e.g. ``192.0.2.30`` or
-``2a02:42fe::4``). The admin represents this as an ``<input type="text">``
-(a single-line input).
+``2a02:42fe::4``). The default form widget for this field is a
+:class:`~django.forms.TextInput`.
The IPv6 address normalization follows :rfc:`4291#section-2.2` section 2.2,
including using the IPv4 format suggested in paragraph 3 of that section, like
@@ -823,8 +823,8 @@ are converted to lowercase.
.. class:: NullBooleanField([**options])
Like a :class:`BooleanField`, but allows ``NULL`` as one of the options. Use
-this instead of a :class:`BooleanField` with ``null=True``. The admin represents
-this as a ``<select>`` box with "Unknown", "Yes" and "No" choices.
+this instead of a :class:`BooleanField` with ``null=True``. The default form
+widget for this field is a :class:`~django.forms.NullBooleanSelect`.
``PositiveIntegerField``
------------------------
@@ -875,8 +875,8 @@ Like an :class:`IntegerField`, but only allows values under a certain
.. class:: TextField([**options])
-A large text field. The admin represents this as a ``<textarea>`` (a multi-line
-input).
+A large text field. The default form widget for this field is a
+:class:`~django.forms.Textarea`.
.. admonition:: MySQL users
@@ -893,8 +893,8 @@ input).
A time, represented in Python by a ``datetime.time`` instance. Accepts the same
auto-population options as :class:`DateField`.
-The admin represents this as an ``<input type="text">`` with some JavaScript
-shortcuts.
+The default form widget for this field is a :class:`~django.forms.TextInput`.
+The admin adds some JavaScript shortcuts.
``URLField``
------------
@@ -903,7 +903,7 @@ shortcuts.
A :class:`CharField` for a URL.
-The admin represents this as an ``<input type="text">`` (a single-line input).
+The default form widget for this field is a :class:`~django.forms.TextInput`.
Like all :class:`CharField` subclasses, :class:`URLField` takes the optional
:attr:`~CharField.max_length`argument. If you don't specify
@@ -979,9 +979,9 @@ define the details of how the relation works.
.. attribute:: ForeignKey.limit_choices_to
A dictionary of lookup arguments and values (see :doc:`/topics/db/queries`)
- that limit the available admin choices for this object. Use this with
- functions from the Python ``datetime`` module to limit choices of objects by
- date. For example::
+ that limit the available admin or ModelForm choices for this object. Use
+ this with functions from the Python ``datetime`` module to limit choices of
+ objects by date. For example::
limit_choices_to = {'pub_date__lte': datetime.now}
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index 14541ad0d1..472ac96457 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -48,7 +48,7 @@ that, you need to :meth:`~Model.save()`.
2. Add a method on a custom manager (usually preferred)::
class BookManager(models.Manager):
- def create_book(title):
+ def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
@@ -386,6 +386,12 @@ perform an update on all fields.
Specifying ``update_fields`` will force an update.
+When saving a model fetched through deferred model loading
+(:meth:`~Model.only()` or :meth:`~Model.defer()`) only the fields loaded from
+the DB will get updated. In effect there is an automatic ``update_fields`` in
+this case. If you assign or change any deferred field value, these fields will
+be added to the updated fields.
+
Deleting objects
================
@@ -453,9 +459,9 @@ using ``__str__()`` like this::
last_name = models.CharField(max_length=50)
def __str__(self):
- # Note use of django.utils.encoding.smart_bytes() here because
+ # Note use of django.utils.encoding.force_bytes() here because
# first_name and last_name will be unicode strings.
- return smart_bytes('%s %s' % (self.first_name, self.last_name))
+ return force_bytes('%s %s' % (self.first_name, self.last_name))
``get_absolute_url``
--------------------
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 8c188c67c3..b59b2ece82 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -1110,6 +1110,14 @@ one, doing so will result in an error.
reader, is slightly faster and consumes a little less memory in the Python
process.
+.. versionchanged:: 1.5
+
+.. note::
+
+ When calling :meth:`~Model.save()` for instances with deferred fields,
+ only the loaded fields will be saved. See :meth:`~Model.save()` for more
+ details.
+
only
~~~~
@@ -1154,6 +1162,14 @@ All of the cautions in the note for the :meth:`defer` documentation apply to
options. Also note that using :meth:`only` and omitting a field requested
using :meth:`select_related` is an error as well.
+.. versionchanged:: 1.5
+
+.. note::
+
+ When calling :meth:`~Model.save()` for instances with deferred fields,
+ only the loaded fields will be saved. See :meth:`~Model.save()` for more
+ details.
+
using
~~~~~
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index 551ee00c6b..21e99de10d 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -731,10 +731,11 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
.. class:: HttpResponseRedirect
- The constructor takes a single argument -- the path to redirect to. This
- can be a fully qualified URL (e.g. ``'http://www.yahoo.com/search/'``) or
- an absolute path with no domain (e.g. ``'/search/'``). Note that this
- returns an HTTP status code 302.
+ The first argument to the constructor is required -- the path to redirect
+ to. This can be a fully qualified URL
+ (e.g. ``'http://www.yahoo.com/search/'``) or an absolute path with no
+ domain (e.g. ``'/search/'``). See :class:`HttpResponse` for other optional
+ constructor arguments. Note that this returns an HTTP status code 302.
.. class:: HttpResponsePermanentRedirect
@@ -743,8 +744,9 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
.. class:: HttpResponseNotModified
- The constructor doesn't take any arguments. Use this to designate that a
- page hasn't been modified since the user's last request (status code 304).
+ The constructor doesn't take any arguments and no content should be added
+ to this response. Use this to designate that a page hasn't been modified
+ since the user's last request (status code 304).
.. class:: HttpResponseBadRequest
@@ -760,8 +762,9 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
.. class:: HttpResponseNotAllowed
- Like :class:`HttpResponse`, but uses a 405 status code. Takes a single,
- required argument: a list of permitted methods (e.g. ``['GET', 'POST']``).
+ Like :class:`HttpResponse`, but uses a 405 status code. The first argument
+ to the constructor is required: a list of permitted methods (e.g.
+ ``['GET', 'POST']``).
.. class:: HttpResponseGone
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 531ff33da2..4729a2b6f1 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -183,7 +183,7 @@ compose a prefix, version and key into a final cache key. The default
implementation is equivalent to the function::
def make_key(key, key_prefix, version):
- return ':'.join([key_prefix, str(version), smart_bytes(key)])
+ return ':'.join([key_prefix, str(version), key])
You may use any key function you want, as long as it has the same
argument signature.
@@ -747,14 +747,15 @@ Did you catch that? NEVER deploy a site into production with :setting:`DEBUG`
turned on.
One of the main features of debug mode is the display of detailed error pages.
-If your app raises an exception when ``DEBUG`` is ``True``, Django will display
-a detailed traceback, including a lot of metadata about your environment, such
-as all the currently defined Django settings (from ``settings.py``).
+If your app raises an exception when :setting:`DEBUG` is ``True``, Django will
+display a detailed traceback, including a lot of metadata about your
+environment, such as all the currently defined Django settings (from
+``settings.py``).
As a security measure, Django will *not* include settings that might be
-sensitive (or offensive), such as ``SECRET_KEY`` or ``PROFANITIES_LIST``.
-Specifically, it will exclude any setting whose name includes any of the
-following:
+sensitive (or offensive), such as :setting:`SECRET_KEY` or
+:setting:`PROFANITIES_LIST`. Specifically, it will exclude any setting whose
+name includes any of the following:
* API
* KEY
@@ -1356,7 +1357,7 @@ MANAGERS
Default: ``()`` (Empty tuple)
A tuple in the same format as :setting:`ADMINS` that specifies who should get
-broken-link notifications when ``SEND_BROKEN_LINK_EMAILS=True``.
+broken-link notifications when :setting:`SEND_BROKEN_LINK_EMAILS` is ``True``.
.. setting:: MEDIA_ROOT
@@ -1365,8 +1366,8 @@ MEDIA_ROOT
Default: ``''`` (Empty string)
-Absolute path to the directory that holds media for this installation, used
-for :doc:`managing stored files </topics/files>`.
+Absolute filesystem path to the directory that will hold :doc:`user-uploaded
+files </topics/files>`.
Example: ``"/var/www/example.com/media/"``
@@ -1537,9 +1538,23 @@ SECRET_KEY
Default: ``''`` (Empty string)
-A secret key for this particular Django installation. Used to provide a seed in
-secret-key hashing algorithms. Set this to a random string -- the longer, the
-better. ``django-admin.py startproject`` creates one automatically.
+A secret key for a particular Django installation. This is used to provide
+:doc:`cryptographic signing </topics/signing>`, and should be set to a unique,
+unpredictable value.
+
+:djadmin:`django-admin.py startproject <startproject>` automatically adds a
+randomly-generated ``SECRET_KEY`` to each new project.
+
+.. warning::
+
+ **Keep this value secret.**
+
+ Running Django with a known :setting:`SECRET_KEY` defeats many of Django's
+ security protections, and can lead to privilege escalation and remote code
+ execution vulnerabilities.
+
+.. versionchanged:: 1.5
+ Django will now refuse to start if :setting:`SECRET_KEY` is not set.
.. setting:: SECURE_PROXY_SSL_HEADER
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index bd2b4c6e9d..48bd346788 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -125,6 +125,10 @@ dot in a variable name, it tries the following lookups, in this order:
* Attribute lookup. Example: ``foo.bar``
* List-index lookup. Example: ``foo[bar]``
+Note that "bar" in a template expression like ``{{ foo.bar }}`` will be
+interpreted as a literal string and not using the value of the variable "bar",
+if one exists in the template context.
+
The template system uses the first lookup type that works. It's short-circuit
logic. Here are a few examples::
@@ -198,6 +202,8 @@ straight lookups. Here are some things to keep in mind:
* A variable can only be called if it has no required arguments. Otherwise,
the system will return an empty string.
+.. _alters-data-description:
+
* Obviously, there can be side effects when calling some variables, and
it'd be either foolish or a security hole to allow the template system
to access them.
@@ -422,6 +428,10 @@ optional, third positional argument, ``processors``. In this example, the
my_data_dictionary,
context_instance=RequestContext(request))
+ Alternatively, use the :meth:`~django.shortcuts.render()` shortcut which is
+ the same as a call to :func:`~django.shortcuts.render_to_response()` with a
+ context_instance argument that forces the use of a ``RequestContext``.
+
Here's what each of the default processors does:
django.contrib.auth.context_processors.auth
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index b6cb1035d3..de19578cac 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -187,6 +187,14 @@ The functions defined in this module share the following properties:
Useful as a mix-in. If you support Python 2 and 3 with a single code base,
you can inherit this mix-in and just define ``__unicode__``.
+.. function:: python_2_unicode_compatible
+
+ A decorator that defines ``__unicode__`` and ``__str__`` methods under
+ Python 2. Under Python 3 it does nothing.
+
+ To support Python 2 and 3 with a single code base, define a ``__str__``
+ method returning text and apply this decorator to the class.
+
.. function:: smart_text(s, encoding='utf-8', strings_only=False, errors='strict')
.. versionadded:: 1.5
@@ -232,14 +240,29 @@ The functions defined in this module share the following properties:
If ``strings_only`` is ``True``, don't convert (some) non-string-like
objects.
+.. function:: force_bytes(s, encoding='utf-8', strings_only=False, errors='strict')
+
+ .. versionadded:: 1.5
+
+ Similar to ``smart_bytes``, except that lazy instances are resolved to
+ bytestrings, rather than kept as lazy objects.
+
+ If ``strings_only`` is ``True``, don't convert (some) non-string-like
+ objects.
+
.. function:: smart_str(s, encoding='utf-8', strings_only=False, errors='strict')
Alias of :func:`smart_bytes` on Python 2 and :func:`smart_text` on Python
- 3. This function always returns a :class:`str`.
+ 3. This function returns a :class:`str` or a lazy string.
For instance, this is suitable for writing to :attr:`sys.stdout` on
Python 2 and 3.
+.. function:: force_str(s, encoding='utf-8', strings_only=False, errors='strict')
+
+ Alias of :func:`force_bytes` on Python 2 and :func:`force_text` on Python
+ 3. This function always returns a :class:`str`.
+
.. function:: iri_to_uri(iri)
Convert an Internationalized Resource Identifier (IRI) portion to a URI
@@ -478,6 +501,33 @@ escaping HTML.
through :func:`conditional_escape` which (ultimately) calls
:func:`~django.utils.encoding.force_text` on the values.
+.. function:: strip_tags(value)
+
+ Removes anything that looks like an html tag from the string, that is
+ anything contained within ``<>``.
+
+ For example::
+
+ 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"``.
+
+.. function:: remove_tags(value, tags)
+
+ Removes a list of [X]HTML tag names from the output.
+
+ For example::
+
+ remove_tags(value, ["b", "span"])
+
+ If ``value`` is ``"<b>Joel</b> <button>is</button> a <span>slug</span>"`` the
+ return value will be ``"Joel <button>is</button> a slug"``.
+
+ Note that this filter is case-sensitive.
+
+ If ``value`` is ``"<B>Joel</B> <button>is</button> a <span>slug</span>"`` the
+ return value will be ``"<B>Joel</B> <button>is</button> a slug"``.
.. _str.format: http://docs.python.org/library/stdtypes.html#str.format
@@ -552,15 +602,29 @@ string" means that the producer of the string has already turned characters
that should not be interpreted by the HTML engine (e.g. '<') into the
appropriate entities.
+.. class:: SafeBytes
+
+ .. versionadded:: 1.5
+
+ A :class:`bytes` subclass that has been specifically marked as "safe"
+ (requires no further escaping) for HTML output purposes.
+
.. class:: SafeString
- A string subclass that has been specifically marked as "safe" (requires no
- further escaping) for HTML output purposes.
+ A :class:`str` subclass that has been specifically marked as "safe"
+ (requires no further escaping) for HTML output purposes. This is
+ :class:`SafeBytes` on Python 2 and :class:`SafeText` on Python 3.
+
+.. class:: SafeText
+
+ .. versionadded:: 1.5
+
+ A :class:`str` (in Python 3) or :class:`unicode` (in Python 2) subclass
+ that has been specifically marked as "safe" for HTML output purposes.
.. class:: SafeUnicode
- A unicode subclass that has been specifically marked as "safe" for HTML
- output purposes.
+ Historical name of :class:`SafeText`. Only available under Python 2.
.. function:: mark_safe(s)
@@ -577,6 +641,24 @@ appropriate entities.
Can be called multiple times on a single string (the resulting escaping is
only applied once).
+``django.utils.text``
+=====================
+
+.. module:: django.utils.text
+ :synopsis: Text manipulation.
+
+.. function:: slugify
+
+ Converts to lowercase, removes non-word characters (alphanumerics and
+ underscores) and converts spaces to hyphens. Also strips leading and trailing
+ whitespace.
+
+ For example::
+
+ slugify(value)
+
+ If ``value`` is ``"Joel is a slug"``, the output will be ``"joel-is-a-slug"``.
+
``django.utils.translation``
============================
diff --git a/docs/releases/1.3.2.txt b/docs/releases/1.3.2.txt
new file mode 100644
index 0000000000..16e00f9732
--- /dev/null
+++ b/docs/releases/1.3.2.txt
@@ -0,0 +1,14 @@
+==========================
+Django 1.3.2 release notes
+==========================
+
+*July 30, 2012*
+
+This is the second security release in the Django 1.3 series, fixing several
+security issues in Django 1.3. Django 1.3.2 is a recommended upgrade for
+all users of Django 1.3.
+
+For a full list of issues addressed in this release, see the `security
+advisory`_.
+
+.. _security advisory: https://www.djangoproject.com/weblog/2012/jul/30/security-releases-issued/
diff --git a/docs/releases/1.4.1.txt b/docs/releases/1.4.1.txt
new file mode 100644
index 0000000000..7c6568e5b5
--- /dev/null
+++ b/docs/releases/1.4.1.txt
@@ -0,0 +1,14 @@
+==========================
+Django 1.4.1 release notes
+==========================
+
+*July 30, 2012*
+
+This is the first security release in the Django 1.4 series, fixing several
+security issues in Django 1.4. Django 1.4.1 is a recommended upgrade for
+all users of Django 1.4.
+
+For a full list of issues addressed in this release, see the `security
+advisory`_.
+
+.. _security advisory: https://www.djangoproject.com/weblog/2012/jul/30/security-releases-issued/
diff --git a/docs/releases/1.4.2.txt b/docs/releases/1.4.2.txt
new file mode 100644
index 0000000000..6f2e9aca2e
--- /dev/null
+++ b/docs/releases/1.4.2.txt
@@ -0,0 +1,14 @@
+==========================
+Django 1.4.2 release notes
+==========================
+
+*TO BE RELEASED*
+
+This is the second security release in the Django 1.4 series.
+
+Backwards incompatible changes
+==============================
+
+* The newly introduced :class:`~django.db.models.GenericIPAddressField`
+ constructor arguments have been adapted to match those of all other model
+ fields. The first two keyword arguments are now verbose_name and name.
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index f789ebde40..5728d8559a 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -42,6 +42,10 @@ keyword argument ``update_fields``. By using this argument it is possible to
save only a select list of model's fields. This can be useful for performance
reasons or when trying to avoid overwriting concurrent changes.
+Deferred instances (those loaded by .only() or .defer()) will automatically
+save just the loaded fields. If any field is set manually after load, that
+field will also get updated on save.
+
See the :meth:`Model.save() <django.db.models.Model.save()>` documentation for
more details.
@@ -80,6 +84,12 @@ By passing ``False`` using this argument it is now possible to retreive the
:class:`ContentType <django.contrib.contenttypes.models.ContentType>`
associated with proxy models.
+New ``view`` variable in class-based views context
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In all :doc:`generic class-based views </topics/class-based-views/index>`
+(or any class-based view inheriting from ``ContextMixin``), the context dictionary
+contains a ``view`` variable that points to the ``View`` instance.
+
Minor features
~~~~~~~~~~~~~~
@@ -134,6 +144,14 @@ year|date:"Y" }}``.
``next_year`` and ``previous_year`` were also added in the context. They are
calculated according to ``allow_empty`` and ``allow_future``.
+Context in TemplateView
+~~~~~~~~~~~~~~~~~~~~~~~
+
+For consistency with the design of the other generic views,
+:class:`~django.views.generic.base.TemplateView` no longer passes a ``params``
+dictionary into the context, instead passing the variables from the URLconf
+directly into the context.
+
OPTIONS, PUT and DELETE requests in the test client
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -154,6 +172,54 @@ If you were using the ``data`` parameter in a PUT request without a
``content_type``, you must encode your data before passing it to the test
client and set the ``content_type`` argument.
+.. _simplejson-incompatibilities:
+
+System version of :mod:`simplejson` no longer used
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:ref:`As explained below <simplejson-deprecation>`, Django 1.5 deprecates
+:mod:`django.utils.simplejson` in favor of Python 2.6's built-in :mod:`json`
+module. In theory, this change is harmless. Unfortunately, because of
+incompatibilities between versions of :mod:`simplejson`, it may trigger errors
+in some circumstances.
+
+JSON-related features in Django 1.4 always used :mod:`django.utils.simplejson`.
+This module was actually:
+
+- A system version of :mod:`simplejson`, if one was available (ie. ``import
+ simplejson`` works), if it was more recent than Django's built-in copy or it
+ had the C speedups, or
+- The :mod:`json` module from the standard library, if it was available (ie.
+ Python 2.6 or greater), or
+- A built-in copy of version 2.0.7 of :mod:`simplejson`.
+
+In Django 1.5, those features use Python's :mod:`json` module, which is based
+on version 2.0.9 of :mod:`simplejson`.
+
+There are no known incompatibilities between Django's copy of version 2.0.7 and
+Python's copy of version 2.0.9. However, there are some incompatibilities
+between other versions of :mod:`simplejson`:
+
+- While the :mod:`simplejson` API is documented as always returning unicode
+ strings, the optional C implementation can return a byte string. This was
+ fixed in Python 2.7.
+- :class:`simplejson.JSONEncoder` gained a ``namedtuple_as_object`` keyword
+ argument in version 2.2.
+
+More information on these incompatibilities is available in `ticket #18023`_.
+
+The net result is that, if you have installed :mod:`simplejson` and your code
+uses Django's serialization internals directly -- for instance
+:class:`django.core.serializers.json.DjangoJSONEncoder`, the switch from
+:mod:`simplejson` to :mod:`json` could break your code. (In general, changes to
+internals aren't documented; we're making an exception here.)
+
+At this point, the maintainers of Django believe that using :mod:`json` from
+the standard library offers the strongest guarantee of backwards-compatibility.
+They recommend to use it from now on.
+
+.. _ticket #18023: https://code.djangoproject.com/ticket/18023#comment:10
+
String types of hasher method parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -161,7 +227,7 @@ If you have written a :ref:`custom password hasher <auth_password_storage>`,
your ``encode()``, ``verify()`` or ``safe_summary()`` methods should accept
Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the
hashing methods need byte strings, you can use the
-:func:`~django.utils.encoding.smart_bytes` utility to encode the strings.
+:func:`~django.utils.encoding.force_bytes` utility to encode the strings.
Validation of previous_page_number and next_page_number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -257,19 +323,38 @@ Miscellaneous
* :func:`~django.utils.http.int_to_base36` properly raises a :exc:`TypeError`
instead of :exc:`ValueError` for non-integer inputs.
+* The ``slugify`` template filter is now available as a standard python
+ function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is
+ available at :func:`django.utils.html.remove_tags`.
+
Features deprecated in 1.5
==========================
+.. _simplejson-deprecation:
+
``django.utils.simplejson``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Since Django 1.5 drops support for Python 2.5, we can now rely on the
-:mod:`json` module being in Python's standard library -- so we've removed
-our own copy of ``simplejson``. You can safely change any use of
-:mod:`django.utils.simplejson` to :mod:`json`.
+:mod:`json` module being available in Python's standard library, so we've
+removed our own copy of :mod:`simplejson`. You should now import :mod:`json`
+instead :mod:`django.utils.simplejson`.
+
+Unfortunately, this change might have unwanted side-effects, because of
+incompatibilities between versions of :mod:`simplejson` -- see the
+:ref:`backwards-incompatible changes <simplejson-incompatibilities>` section.
+If you rely on features added to :mod:`simplejson` after it became Python's
+:mod:`json`, you should import :mod:`simplejson` explicitly.
``itercompat.product``
~~~~~~~~~~~~~~~~~~~~~~
The :func:`~django.utils.itercompat.product` function has been deprecated. Use
the built-in :func:`itertools.product` instead.
+
+``django.utils.encoding.StrAndUnicode``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :class:`~django.utils.encoding.StrAndUnicode` mix-in has been deprecated.
+Define a ``__str__`` method and apply the
+:func:`~django.utils.encoding.python_2_unicode_compatible` decorator instead.
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index e38ab646d6..fa55a4d206 100644
--- a/docs/releases/index.txt
+++ b/docs/releases/index.txt
@@ -27,6 +27,8 @@ Final releases
.. toctree::
:maxdepth: 1
+ .. 1.4.2 (uncomment on release)
+ 1.4.1
1.4
1.3 release
@@ -34,6 +36,7 @@ Final releases
.. toctree::
:maxdepth: 1
+ 1.3.2
1.3.1
1.3
diff --git a/docs/topics/auth.txt b/docs/topics/auth.txt
index 307691bd4a..f8dbbb65a6 100644
--- a/docs/topics/auth.txt
+++ b/docs/topics/auth.txt
@@ -460,7 +460,7 @@ algorithm.
Increasing the work factor
~~~~~~~~~~~~~~~~~~~~~~~~~~
-The PDKDF2 and bcrypt algorithms use a number of iterations or rounds of
+The PBKDF2 and bcrypt algorithms use a number of iterations or rounds of
hashing. This deliberately slows down attackers, making attacks against hashed
passwords harder. However, as computing power increases, the number of
iterations needs to be increased. We've chosen a reasonable default (and will
@@ -468,7 +468,7 @@ increase it with each release of Django), but you may wish to tune it up or
down, depending on your security needs and available processing power. To do so,
you'll subclass the appropriate algorithm and override the ``iterations``
parameters. For example, to increase the number of iterations used by the
-default PDKDF2 algorithm:
+default PBKDF2 algorithm:
1. Create a subclass of ``django.contrib.auth.hashers.PBKDF2PasswordHasher``::
@@ -1170,24 +1170,25 @@ includes a few other useful built-in views located in
:file:`registration/password_reset_form.html` if not supplied.
* ``email_template_name``: The full name of a template to use for
- generating the email with the new password. Defaults to
+ generating the email with the reset password link. Defaults to
:file:`registration/password_reset_email.html` if not supplied.
* ``subject_template_name``: The full name of a template to use for
- the subject of the email with the new password. Defaults
+ the subject of the email with the reset password link. Defaults
to :file:`registration/password_reset_subject.txt` if not supplied.
.. versionadded:: 1.4
- * ``password_reset_form``: Form that will be used to set the password.
- Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
+ * ``password_reset_form``: Form that will be used to get the email of
+ the user to reset the password for. Defaults to
+ :class:`~django.contrib.auth.forms.PasswordResetForm`.
- * ``token_generator``: Instance of the class to check the password. This
- will default to ``default_token_generator``, it's an instance of
+ * ``token_generator``: Instance of the class to check the one time link.
+ This will default to ``default_token_generator``, it's an instance of
``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
* ``post_reset_redirect``: The URL to redirect to after a successful
- password change.
+ password reset request.
* ``from_email``: A valid email address. By default Django uses
the :setting:`DEFAULT_FROM_EMAIL`.
@@ -1218,7 +1219,7 @@ includes a few other useful built-in views located in
* ``uid``: The user's id encoded in base 36.
- * ``token``: Token to check that the password is valid.
+ * ``token``: Token to check that the reset link is valid.
Sample ``registration/password_reset_email.html`` (email body template):
diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
index 219b6c7795..f13238e342 100644
--- a/docs/topics/cache.txt
+++ b/docs/topics/cache.txt
@@ -864,7 +864,7 @@ key version to provide a final cache key. By default, the three parts
are joined using colons to produce a final string::
def make_key(key, key_prefix, version):
- return ':'.join([key_prefix, str(version), smart_bytes(key)])
+ return ':'.join([key_prefix, str(version), key])
If you want to combine the parts in different ways, or apply other
processing to the final key (e.g., taking a hash digest of the key
diff --git a/docs/topics/class-based-views/index.txt b/docs/topics/class-based-views/index.txt
index 1ac70e6938..6637bd5fcb 100644
--- a/docs/topics/class-based-views/index.txt
+++ b/docs/topics/class-based-views/index.txt
@@ -11,8 +11,7 @@ to structure your views and reuse code by harnessing inheritance and
mixins. There are also some generic views for simple tasks which we'll
get to later, but you may want to design your own structure of
reusable views which suits your use case. For full details, see the
-:doc:`class-based views reference
-documentation</ref/class-based-views/index>`.
+:doc:`class-based views reference documentation</ref/class-based-views/index>`.
.. toctree::
:maxdepth: 1
@@ -32,41 +31,12 @@ redirect, and :class:`~django.views.generic.base.TemplateView` extends the base
to make it also render a template.
-Simple usage
-============
-
-Class-based generic views (and any class-based views that inherit from
-the base classes Django provides) can be configured in two
-ways: subclassing, or passing in arguments directly in the URLconf.
-
-When you subclass a class-based view, you can override attributes
-(such as the ``template_name``) or methods (such as ``get_context_data``)
-in your subclass to provide new values or methods. Consider, for example,
-a view that just displays one template, ``about.html``. Django has a
-generic view to do this - :class:`~django.views.generic.base.TemplateView` -
-so we can just subclass it, and override the template name::
-
- # some_app/views.py
- from django.views.generic import TemplateView
-
- class AboutView(TemplateView):
- template_name = "about.html"
-
-Then, we just need to add this new view into our URLconf. As the class-based
-views themselves are classes, we point the URL to the ``as_view`` class method
-instead, which is the entry point for class-based views::
-
- # urls.py
- from django.conf.urls import patterns, url, include
- from some_app.views import AboutView
-
- urlpatterns = patterns('',
- (r'^about/', AboutView.as_view()),
- )
+Simple usage in your URLconf
+============================
-Alternatively, if you're only changing a few simple attributes on a
-class-based view, you can simply pass the new attributes into the ``as_view``
-method call itself::
+The simplest way to use generic views is to create them directly in your
+URLconf. If you're only changing a few simple attributes on a class-based view,
+you can simply pass them into the ``as_view`` method call itself::
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
@@ -75,93 +45,41 @@ method call itself::
(r'^about/', TemplateView.as_view(template_name="about.html")),
)
+Any arguments given will override the ``template_name`` on the
A similar overriding pattern can be used for the ``url`` attribute on
:class:`~django.views.generic.base.RedirectView`.
-.. _jsonresponsemixin-example:
-
-More than just HTML
--------------------
-Where class based views shine is when you want to do the same thing many times.
-Suppose you're writing an API, and every view should return JSON instead of
-rendered HTML.
+Subclassing generic views
+=========================
-We can create a mixin class to use in all of our views, handling the
-conversion to JSON once.
+The second, more powerful way to use generic views is to inherit from an
+existing view and override attributes (such as the ``template_name``) or
+methods (such as ``get_context_data``) in your subclass to provide new values
+or methods. Consider, for example, a view that just displays one template,
+``about.html``. Django has a generic view to do this -
+:class:`~django.views.generic.base.TemplateView` - so we can just subclass it,
+and override the template name::
-For example, a simple JSON mixin might look something like this::
-
- import json
- from django.http import HttpResponse
-
- class JSONResponseMixin(object):
- """
- A mixin that can be used to render a JSON response.
- """
- response_class = HttpResponse
-
- def render_to_response(self, context, **response_kwargs):
- """
- Returns a JSON response, transforming 'context' to make the payload.
- """
- response_kwargs['content_type'] = 'application/json'
- return self.response_class(
- self.convert_context_to_json(context),
- **response_kwargs
- )
-
- def convert_context_to_json(self, context):
- "Convert the context dictionary into a JSON object"
- # Note: This is *EXTREMELY* naive; in reality, you'll need
- # to do much more complex handling to ensure that arbitrary
- # objects -- such as Django model instances or querysets
- # -- can be serialized as JSON.
- return json.dumps(context)
-
-Now we mix this into the base view::
-
- from django.views.generic import View
-
- class JSONView(JSONResponseMixin, View):
- pass
-
-Equally we could use our mixin with one of the generic views. We can make our
-own version of :class:`~django.views.generic.detail.DetailView` by mixing
-:class:`JSONResponseMixin` with the
-:class:`~django.views.generic.detail.BaseDetailView` -- (the
-:class:`~django.views.generic.detail.DetailView` before template
-rendering behavior has been mixed in)::
+ # some_app/views.py
+ from django.views.generic import TemplateView
- class JSONDetailView(JSONResponseMixin, BaseDetailView):
- pass
+ class AboutView(TemplateView):
+ template_name = "about.html"
-This view can then be deployed in the same way as any other
-:class:`~django.views.generic.detail.DetailView`, with exactly the
-same behavior -- except for the format of the response.
+Then we just need to add this new view into our URLconf.
+`~django.views.generic.base.TemplateView` is a class, not a function, so we
+point the URL to the ``as_view`` class method instead, which provides a
+function-like entry to class-based views::
-If you want to be really adventurous, you could even mix a
-:class:`~django.views.generic.detail.DetailView` subclass that is able
-to return *both* HTML and JSON content, depending on some property of
-the HTTP request, such as a query argument or a HTTP header. Just mix
-in both the :class:`JSONResponseMixin` and a
-:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
-and override the implementation of :func:`render_to_response()` to defer
-to the appropriate subclass depending on the type of response that the user
-requested::
+ # urls.py
+ from django.conf.urls import patterns, url, include
+ from some_app.views import AboutView
- class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
- def render_to_response(self, context):
- # Look for a 'format=json' GET argument
- if self.request.GET.get('format','html') == 'json':
- return JSONResponseMixin.render_to_response(self, context)
- else:
- return SingleObjectTemplateResponseMixin.render_to_response(self, context)
+ urlpatterns = patterns('',
+ (r'^about/', AboutView.as_view()),
+ )
-Because of the way that Python resolves method overloading, the local
-``render_to_response()`` implementation will override the versions provided by
-:class:`JSONResponseMixin` and
-:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
For more information on how to use the built in generic views, consult the next
topic on :doc:`generic class based views</topics/class-based-views/generic-display>`.
@@ -171,16 +89,15 @@ Decorating class-based views
.. highlightlang:: python
-The extension of class-based views isn't limited to using mixins. You
-can use also use decorators.
+Since class-based views aren't functions, decorating them works differently
+depending on if you're using ``as_view`` or creating a subclass.
Decorating in URLconf
---------------------
The simplest way of decorating class-based views is to decorate the
result of the :meth:`~django.views.generic.base.View.as_view` method.
-The easiest place to do this is in the URLconf where you deploy your
-view::
+The easiest place to do this is in the URLconf where you deploy your view::
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
diff --git a/docs/topics/class-based-views/mixins.txt b/docs/topics/class-based-views/mixins.txt
index 0c19d60e35..f07769fb8a 100644
--- a/docs/topics/class-based-views/mixins.txt
+++ b/docs/topics/class-based-views/mixins.txt
@@ -69,7 +69,7 @@ interface to working with templates in class-based views.
add more members to the dictionary.
Building up Django's generic class-based views
-===============================================
+==============================================
Let's look at how two of Django's generic class-based views are built
out of mixins providing discrete functionality. We'll consider
@@ -222,8 +222,7 @@ we'll want the functionality provided by
:class:`~django.views.generic.detail.SingleObjectMixin`.
We'll demonstrate this with the publisher modelling we used in the
-:doc:`generic class-based views
-introduction<generic-display>`.
+:doc:`generic class-based views introduction<generic-display>`.
.. code-block:: python
@@ -233,11 +232,11 @@ introduction<generic-display>`.
from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin
from books.models import Author
-
+
class RecordInterest(View, SingleObjectMixin):
"""Records the current user's interest in an author."""
model = Author
-
+
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return HttpResponseForbidden()
@@ -256,9 +255,7 @@ we're interested in, which it just does with a simple call to
``self.get_object()``. Everything else is taken care of for us by the
mixin.
-We can hook this into our URLs easily enough:
-
-.. code-block:: python
+We can hook this into our URLs easily enough::
# urls.py
from books.views import RecordInterest
@@ -294,8 +291,6 @@ object. In order to do this, we need to have two different querysets:
We'll figure that out ourselves in :meth:`get_queryset()` so we
can take into account the Publisher we're looking at.
-.. highlightlang:: python
-
.. note::
We have to think carefully about :meth:`get_context_data()`.
@@ -311,15 +306,15 @@ Now we can write a new :class:`PublisherDetail`::
from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher
-
+
class PublisherDetail(SingleObjectMixin, ListView):
paginate_by = 2
template_name = "books/publisher_detail.html"
-
+
def get_context_data(self, **kwargs):
kwargs['publisher'] = self.object
return super(PublisherDetail, self).get_context_data(**kwargs)
-
+
def get_queryset(self):
self.object = self.get_object(Publisher.objects.all())
return self.object.book_set.all()
@@ -339,26 +334,26 @@ have to create lots of books to see the pagination working! Here's the
template you'd want to use::
{% extends "base.html" %}
-
+
{% block content %}
<h2>Publisher {{ publisher.name }}</h2>
-
+
<ol>
{% for book in page_obj %}
<li>{{ book.title }}</li>
{% endfor %}
</ol>
-
+
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
-
+
<span class="current">
Page {{ page_obj.number }} of {{ paginator.num_pages }}.
</span>
-
+
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
{% endif %}
@@ -428,9 +423,9 @@ code so that on ``POST`` the form gets called appropriately.
the views implement :meth:`get()`, and things would get much more
confusing.
-Our new :class:`AuthorDetail` looks like this:
+.. highlightlang:: python
-.. code-block:: python
+Our new :class:`AuthorDetail` looks like this::
# CAUTION: you almost certainly do not want to do this.
# It is provided as part of a discussion of problems you can
@@ -455,7 +450,7 @@ Our new :class:`AuthorDetail` looks like this:
'author-detail',
kwargs = {'pk': self.object.pk},
)
-
+
def get_context_data(self, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
@@ -464,7 +459,7 @@ Our new :class:`AuthorDetail` looks like this:
}
context.update(kwargs)
return super(AuthorDetail, self).get_context_data(**context)
-
+
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
@@ -472,14 +467,14 @@ Our new :class:`AuthorDetail` looks like this:
return self.form_valid(form)
else:
return self.form_invalid(form)
-
+
def form_valid(self, form):
if not self.request.user.is_authenticated():
return HttpResponseForbidden()
self.object = self.get_object()
# record the interest using the message in form.cleaned_data
return super(AuthorDetail, self).form_valid(form)
-
+
:meth:`get_success_url()` is just providing somewhere to redirect to,
which gets used in the default implementation of
:meth:`form_valid()`. We have to provide our own :meth:`post()` as
@@ -525,21 +520,21 @@ write our own :meth:`get_context_data()` to make the
from django.views.generic import DetailView
from django import forms
from books.models import Author
-
+
class AuthorInterestForm(forms.Form):
message = forms.CharField()
-
+
class AuthorDisplay(DetailView):
-
+
queryset = Author.objects.all()
-
+
def get_context_data(self, **kwargs):
context = {
'form': AuthorInterestForm(),
}
context.update(kwargs)
return super(AuthorDisplay, self).get_context_data(**context)
-
+
Then the :class:`AuthorInterest` is a simple :class:`FormView`, but we
have to bring in :class:`SingleObjectMixin` so we can find the author
we're talking about, and we have to remember to set
@@ -550,7 +545,7 @@ template as :class:`AuthorDisplay` is using on ``GET``.
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
-
+
class AuthorInterest(FormView, SingleObjectMixin):
template_name = 'books/author_detail.html'
form_class = AuthorInterestForm
@@ -561,13 +556,13 @@ template as :class:`AuthorDisplay` is using on ``GET``.
'object': self.get_object(),
}
return super(AuthorInterest, self).get_context_data(**context)
-
+
def get_success_url(self):
return reverse(
'author-detail',
kwargs = {'pk': self.object.pk},
)
-
+
def form_valid(self, form):
if not self.request.user.is_authenticated():
return HttpResponseForbidden()
@@ -588,13 +583,13 @@ using a different template.
.. code-block:: python
from django.views.generic import View
-
+
class AuthorDetail(View):
-
+
def get(self, request, *args, **kwargs):
view = AuthorDisplay.as_view()
return view(request, *args, **kwargs)
-
+
def post(self, request, *args, **kwargs):
view = AuthorInterest.as_view()
return view(request, *args, **kwargs)
@@ -603,3 +598,88 @@ This approach can also be used with any other generic class-based
views or your own class-based views inheriting directly from
:class:`View` or :class:`TemplateView`, as it keeps the different
views as separate as possible.
+
+.. _jsonresponsemixin-example:
+
+More than just HTML
+===================
+
+Where class based views shine is when you want to do the same thing many times.
+Suppose you're writing an API, and every view should return JSON instead of
+rendered HTML.
+
+We can create a mixin class to use in all of our views, handling the
+conversion to JSON once.
+
+For example, a simple JSON mixin might look something like this::
+
+ import json
+ from django.http import HttpResponse
+
+ class JSONResponseMixin(object):
+ """
+ A mixin that can be used to render a JSON response.
+ """
+ response_class = HttpResponse
+
+ def render_to_response(self, context, **response_kwargs):
+ """
+ Returns a JSON response, transforming 'context' to make the payload.
+ """
+ response_kwargs['content_type'] = 'application/json'
+ return self.response_class(
+ self.convert_context_to_json(context),
+ **response_kwargs
+ )
+
+ def convert_context_to_json(self, context):
+ "Convert the context dictionary into a JSON object"
+ # Note: This is *EXTREMELY* naive; in reality, you'll need
+ # to do much more complex handling to ensure that arbitrary
+ # objects -- such as Django model instances or querysets
+ # -- can be serialized as JSON.
+ return json.dumps(context)
+
+Now we mix this into the base TemplateView::
+
+ from django.views.generic import TemplateView
+
+ class JSONView(JSONResponseMixin, TemplateView):
+ pass
+
+Equally we could use our mixin with one of the generic views. We can make our
+own version of :class:`~django.views.generic.detail.DetailView` by mixing
+:class:`JSONResponseMixin` with the
+:class:`~django.views.generic.detail.BaseDetailView` -- (the
+:class:`~django.views.generic.detail.DetailView` before template
+rendering behavior has been mixed in)::
+
+ class JSONDetailView(JSONResponseMixin, BaseDetailView):
+ pass
+
+This view can then be deployed in the same way as any other
+:class:`~django.views.generic.detail.DetailView`, with exactly the
+same behavior -- except for the format of the response.
+
+If you want to be really adventurous, you could even mix a
+:class:`~django.views.generic.detail.DetailView` subclass that is able
+to return *both* HTML and JSON content, depending on some property of
+the HTTP request, such as a query argument or a HTTP header. Just mix
+in both the :class:`JSONResponseMixin` and a
+:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
+and override the implementation of :func:`render_to_response()` to defer
+to the appropriate subclass depending on the type of response that the user
+requested::
+
+ class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
+ def render_to_response(self, context):
+ # Look for a 'format=json' GET argument
+ if self.request.GET.get('format','html') == 'json':
+ return JSONResponseMixin.render_to_response(self, context)
+ else:
+ return SingleObjectTemplateResponseMixin.render_to_response(self, context)
+
+Because of the way that Python resolves method overloading, the local
+``render_to_response()`` implementation will override the versions provided by
+:class:`JSONResponseMixin` and
+:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt
index ce15dc9535..f29cc28332 100644
--- a/docs/topics/db/models.txt
+++ b/docs/topics/db/models.txt
@@ -108,8 +108,8 @@ determine a few things:
* The database column type (e.g. ``INTEGER``, ``VARCHAR``).
-* The :doc:`widget </ref/forms/widgets>` to use in Django's admin interface,
- if you care to use it (e.g. ``<input type="text">``, ``<select>``).
+* The default :doc:`widget </ref/forms/widgets>` to use when rendering a form
+ field (e.g. ``<input type="text">``, ``<select>``).
* The minimal validation requirements, used in Django's admin and in
automatically-generated forms.
@@ -143,13 +143,13 @@ ones:
Note that this is different than :attr:`~Field.null`.
:attr:`~Field.null` is purely database-related, whereas
:attr:`~Field.blank` is validation-related. If a field has
- :attr:`blank=True <Field.blank>`, validation on Django's admin site will
+ :attr:`blank=True <Field.blank>`, form validation will
allow entry of an empty value. If a field has :attr:`blank=False
<Field.blank>`, the field will be required.
:attr:`~Field.choices`
An iterable (e.g., a list or tuple) of 2-tuples to use as choices for
- this field. If this is given, Django's admin will use a select box
+ this field. If this is given, the default form widget will be a select box
instead of the standard text field and will limit choices to the choices
given.
@@ -164,7 +164,7 @@ ones:
)
The first element in each tuple is the value that will be stored in the
- database, the second element will be displayed by the admin interface,
+ database, the second element will be displayed by the default form widget
or in a ModelChoiceField. Given an instance of a model object, the
display value for a choices field can be accessed using the
``get_FOO_display`` method. For example::
@@ -195,9 +195,8 @@ ones:
created.
:attr:`~Field.help_text`
- Extra "help" text to be displayed under the field on the object's admin
- form. It's useful for documentation even if your object doesn't have an
- admin form.
+ Extra "help" text to be displayed with the form widget. It's useful for
+ documentation even if your field isn't used on a form.
:attr:`~Field.primary_key`
If ``True``, this field is the primary key for the model.
@@ -360,13 +359,12 @@ It doesn't matter which model has the
:class:`~django.db.models.ManyToManyField`, but you should only put it in one
of the models -- not both.
-Generally, :class:`~django.db.models.ManyToManyField` instances should go in the
-object that's going to be edited in the admin interface, if you're using
-Django's admin. In the above example, ``toppings`` is in ``Pizza`` (rather than
-``Topping`` having a ``pizzas`` :class:`~django.db.models.ManyToManyField` )
-because it's more natural to think about a pizza having toppings than a
-topping being on multiple pizzas. The way it's set up above, the ``Pizza`` admin
-form would let users select the toppings.
+Generally, :class:`~django.db.models.ManyToManyField` instances should go in
+the object that's going to be edited on a form. In the above example,
+``toppings`` is in ``Pizza`` (rather than ``Topping`` having a ``pizzas``
+:class:`~django.db.models.ManyToManyField` ) because it's more natural to think
+about a pizza having toppings than a topping being on multiple pizzas. The way
+it's set up above, the ``Pizza`` form would let users select the toppings.
.. seealso::
diff --git a/docs/topics/db/multi-db.txt b/docs/topics/db/multi-db.txt
index 86e785a19d..03a7d3b7cd 100644
--- a/docs/topics/db/multi-db.txt
+++ b/docs/topics/db/multi-db.txt
@@ -525,7 +525,7 @@ registered with any ``Admin`` instance::
admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)
- othersite = admin.Site('othersite')
+ othersite = admin.AdminSite('othersite')
othersite.register(Publisher, MultiDBModelAdmin)
This example sets up two admin sites. On the first site, the
diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt
index b4d4eb1062..60437c1120 100644
--- a/docs/topics/db/queries.txt
+++ b/docs/topics/db/queries.txt
@@ -900,10 +900,10 @@ possible to easily create new instance with all fields' values copied. In the
simplest case, you can just set ``pk`` to ``None``. Using our blog example::
blog = Blog(name='My blog', tagline='Blogging is easy')
- blog.save() # post.pk == 1
+ blog.save() # blog.pk == 1
blog.pk = None
- blog.save() # post.pk == 2
+ blog.save() # blog.pk == 2
Things get more complicated if you use inheritance. Consider a subclass of
``Blog``::
diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt
index 4399e7572c..615dd7193c 100644
--- a/docs/topics/forms/media.txt
+++ b/docs/topics/forms/media.txt
@@ -65,9 +65,9 @@ through this property::
>>> w = CalendarWidget()
>>> print(w.media)
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
Here's a list of all possible ``Media`` options. There are no required options.
@@ -110,9 +110,9 @@ requirements::
If this last CSS definition were to be rendered, it would become the following HTML::
- <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
- <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
- <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
+ <link href="http://static.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
+ <link href="http://static.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
+ <link href="http://static.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
``js``
~~~~~~
@@ -140,11 +140,11 @@ basic Calendar widget from the example above::
>>> w = FancyCalendarWidget()
>>> print(w.media)
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <link href="http://static.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
The FancyCalendar widget inherits all the media from it's parent widget. If
you don't want media to be inherited in this way, add an ``extend=False``
@@ -160,8 +160,8 @@ declaration to the media declaration::
>>> w = FancyCalendarWidget()
>>> print(w.media)
- <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+ <link href="http://static.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
If you require even more control over media inheritance, define your media
using a `dynamic property`_. Dynamic properties give you complete control over
@@ -253,12 +253,12 @@ to filter out a medium of interest. For example::
>>> w = CalendarWidget()
>>> print(w.media)
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
>>> print(w.media)['css']
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
When you use the subscript operator, the value that is returned is a new
Media object -- but one that only contains the media of interest.
@@ -283,10 +283,10 @@ the resulting Media object contains the union of the media from both files::
>>> w1 = CalendarWidget()
>>> w2 = OtherWidget()
>>> print(w1.media + w2.media)
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
Media on Forms
--------------
@@ -306,10 +306,10 @@ of adding the media definitions for all widgets that are part of the form::
>>> f = ContactForm()
>>> f.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
If you want to associate additional media with a form -- for example, CSS for form
layout -- simply add a media declaration to the form::
@@ -325,8 +325,8 @@ layout -- simply add a media declaration to the form::
>>> f = ContactForm()
>>> f.media
- <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
- <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
- <script type="text/javascript" src="http://media.example.com/animations.js"></script>
- <script type="text/javascript" src="http://media.example.com/actions.js"></script>
- <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+ <link href="http://static.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <link href="http://static.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://static.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://static.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index 0ca37745c7..8159c8850c 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -200,7 +200,9 @@ The first time you call ``is_valid()`` or access the ``errors`` attribute of a
well as :ref:`model validation <validating-objects>`. This has the side-effect
of cleaning the model you pass to the ``ModelForm`` constructor. For instance,
calling ``is_valid()`` on your form will convert any date fields on your model
-to actual date objects.
+to actual date objects. If form validation fails, only some of the updates
+may be applied. For this reason, you'll probably want to avoid reusing the
+model instance.
The ``save()`` method
diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt
index 877d3b4100..b3a830c25e 100644
--- a/docs/topics/http/file-uploads.txt
+++ b/docs/topics/http/file-uploads.txt
@@ -178,6 +178,52 @@ Three settings control Django's file upload behavior:
Which means "try to upload to memory first, then fall back to temporary
files."
+Handling uploaded files with a model
+------------------------------------
+
+If you're saving a file on a :class:`~django.db.models.Model` with a
+:class:`~django.db.models.FileField`, using a :class:`~django.forms.ModelForm`
+makes this process much easier. The file object will be saved to the location
+specified by the :attr:`~django.db.models.FileField.upload_to` argument of the
+corresponding :class:`~django.db.models.FileField` when calling
+``form.save()``::
+
+ from django.http import HttpResponseRedirect
+ from django.shortcuts import render
+ from .forms import ModelFormWithFileField
+
+ def upload_file(request):
+ if request.method == 'POST':
+ form = ModelFormWithFileField(request.POST, request.FILES)
+ if form.is_valid():
+ # file is saved
+ form.save()
+ return HttpResponseRedirect('/success/url/')
+ else:
+ form = ModelFormWithFileField()
+ return render('upload.html', {'form': form})
+
+If you are constructing an object manually, you can simply assign the file
+object from :attr:`request.FILES <django.http.HttpRequest.FILES>` to the file
+field in the model::
+
+ from django.http import HttpResponseRedirect
+ from django.shortcuts import render
+ from .forms import UploadFileForm
+ from .models import ModelWithFileField
+
+ def upload_file(request):
+ if request.method == 'POST':
+ form = UploadFileForm(request.POST, request.FILES)
+ if form.is_valid():
+ instance = ModelWithFileField(file_field=request.FILES['file'])
+ instance.save()
+ return HttpResponseRedirect('/success/url/')
+ else:
+ form = UploadFileForm()
+ return render('upload.html', {'form': form})
+
+
``UploadedFile`` objects
========================
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 4e75dfe55f..7297184ed3 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -314,6 +314,9 @@ that should be called if none of the URL patterns match.
By default, this is ``'django.views.defaults.page_not_found'``. That default
value should suffice.
+See the documentation about :ref:`the 404 (HTTP Not Found) view
+<http_not_found_view>` for more information.
+
handler500
----------
@@ -326,6 +329,9 @@ have runtime errors in view code.
By default, this is ``'django.views.defaults.server_error'``. That default
value should suffice.
+See the documentation about :ref:`the 500 (HTTP Internal Server Error) view
+<http_internal_server_error_view>` for more information.
+
Notes on capturing text in URLs
===============================
@@ -568,10 +574,8 @@ For example::
(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)
-In this example, for a request to ``/blog/2005/``, Django will call the
-``blog.views.year_archive()`` view, passing it these keyword arguments::
-
- year='2005', foo='bar'
+In this example, for a request to ``/blog/2005/``, Django will call
+``blog.views.year_archive(year='2005', foo='bar')``.
This technique is used in the
:doc:`syndication framework </ref/contrib/syndication>` to pass metadata and
diff --git a/docs/topics/http/views.txt b/docs/topics/http/views.txt
index a8c85ddf6e..c4bd15e72e 100644
--- a/docs/topics/http/views.txt
+++ b/docs/topics/http/views.txt
@@ -127,6 +127,8 @@ called ``404.html`` and located in the top level of your template tree.
Customizing error views
=======================
+.. _http_not_found_view:
+
The 404 (page not found) view
-----------------------------
@@ -167,6 +169,8 @@ Four things to note about 404 views:
your 404 view will never be used, and your URLconf will be displayed
instead, with some debug information.
+.. _http_internal_server_error_view:
+
The 500 (server error) view
----------------------------
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index bdbb04823d..9bd53da2b9 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -37,6 +37,13 @@ from your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
controls if Django should implement format localization. See
:doc:`/topics/i18n/formatting` for more details.
+.. note::
+
+ Make sure you've activated translation for your project (the fastest way is
+ to check if :setting:`MIDDLEWARE_CLASSES` includes
+ :mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet,
+ see :ref:`how-django-discovers-language-preference`.
+
Internationalization: in Python code
====================================
@@ -317,10 +324,10 @@ 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.utils.translation import ugettext_lazy
+ from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
- name = models.CharField(help_text=ugettext_lazy('This is the help text'))
+ name = models.CharField(help_text=_('This is the help text'))
You can mark names of ``ForeignKey``, ``ManyTomanyField`` or ``OneToOneField``
relationship as translatable by using their ``verbose_name`` options::
@@ -344,14 +351,14 @@ It is recommended to always provide explicit
relying on the fallback English-centric and somewhat naïve determination of
verbose names Django performs bu looking at the model's class name::
- from django.utils.translation import ugettext_lazy
+ from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
- name = models.CharField(_('name'), help_text=ugettext_lazy('This is the help text'))
+ name = models.CharField(_('name'), help_text=_('This is the help text'))
class Meta:
- verbose_name = ugettext_lazy('my thing')
- verbose_name_plural = ugettext_lazy('my things')
+ verbose_name = _('my thing')
+ verbose_name_plural = _('my things')
Model methods ``short_description`` attribute values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -456,6 +463,9 @@ Internationalization: in template code
Translations in :doc:`Django templates </topics/templates>` uses two template
tags and a slightly different syntax than in Python code. To give your template
access to these tags, put ``{% load i18n %}`` toward the top of your template.
+As with all template tags, this tag needs to be loaded in all templates which
+use translations, even those templates that extend from other templates which
+have already loaded the ``i18n`` tag.
.. templatetag:: trans
diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt
index a878d42266..b54a9475ae 100644
--- a/docs/topics/logging.txt
+++ b/docs/topics/logging.txt
@@ -218,10 +218,11 @@ handlers, filters and formatters that you want in your logging setup,
and the log levels and other properties that you want those components
to have.
-Logging is configured immediately after settings have been loaded.
-Since the loading of settings is one of the first things that Django
-does, you can be certain that loggers are always ready for use in your
-project code.
+Logging is configured as soon as settings have been loaded
+(either manually using :func:`~django.conf.settings.configure` or when at least
+one setting is accessed). Since the loading of settings is one of the first
+things that Django does, you can be certain that loggers are always ready for
+use in your project code.
.. _dictConfig format: http://docs.python.org/library/logging.config.html#configuration-dictionary-schema
@@ -515,6 +516,35 @@ logging module.
through the filter. Handling of that record will not proceed if the callback
returns False.
+ For instance, to filter out :class:`~django.http.UnreadablePostError`
+ (raised when a user cancels an upload) from the admin emails, you would
+ create a filter function::
+
+ from django.http import UnreadablePostError
+
+ def skip_unreadable_post(record):
+ if record.exc_info:
+ exc_type, exc_value = record.exc_info[:2]
+ if isinstance(exc_value, UnreadablePostError):
+ return False
+ return True
+
+ and then add it to your logging config::
+
+ 'filters': {
+ 'skip_unreadable_posts': {
+ '()': 'django.utils.log.CallbackFilter',
+ 'callback': skip_unreadable_post,
+ }
+ },
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['skip_unreadable_posts'],
+ 'class': 'django.utils.log.AdminEmailHandler'
+ }
+ },
+
.. class:: RequireDebugFalse()
.. versionadded:: 1.4
diff --git a/docs/topics/python3.txt b/docs/topics/python3.txt
index b09c1d2347..457486caa4 100644
--- a/docs/topics/python3.txt
+++ b/docs/topics/python3.txt
@@ -1,25 +1,213 @@
-======================
-Python 3 compatibility
-======================
+===================
+Porting to Python 3
+===================
Django 1.5 is the first version of Django to support Python 3. The same code
runs both on Python 2 (≥ 2.6.5) and Python 3 (≥ 3.2), thanks to the six_
-compatibility layer and ``unicode_literals``.
+compatibility layer.
.. _six: http://packages.python.org/six/
-This document is not meant as a Python 2 to Python 3 migration guide. There
-are many existing resources, including `Python's official porting guide`_.
-Rather, it describes guidelines that apply to Django's code and are
-recommended for pluggable apps that run with both Python 2 and 3.
+This document is primarily targeted at authors of pluggable application
+who want to support both Python 2 and 3. It also describes guidelines that
+apply to Django's code.
+
+Philosophy
+==========
+
+This document assumes that you are familiar with the changes between Python 2
+and Python 3. If you aren't, read `Python's official porting guide`_ first.
+Refreshing your knowledge of unicode handling on Python 2 and 3 will help; the
+`Pragmatic Unicode`_ presentation is a good resource.
+
+Django uses the *Python 2/3 Compatible Source* strategy. Of course, you're
+free to chose another strategy for your own code, especially if you don't need
+to stay compatible with Python 2. But authors of pluggable applications are
+encouraged to use the same porting strategy as Django itself.
+
+Writing compatible code is much easier if you target Python ≥ 2.6. You will
+most likely take advantage of the compatibility functions introduced in Django
+1.5, like :mod:`django.utils.six`, so your application will also require
+Django ≥ 1.5.
+
+Obviously, writing compatible source code adds some overhead, and that can
+cause frustration. Django's developers have found that attempting to write
+Python 3 code that's compatible with Python 2 is much more rewarding than the
+opposite. Not only does that make your code more future-proof, but Python 3's
+advantages (like the saner string handling) start shining quickly. Dealing
+with Python 2 becomes a backwards compatibility requirement, and we as
+developers are used to dealing with such constraints.
+
+Porting tools provided by Django are inspired by this philosophy, and it's
+reflected throughout this guide.
.. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html
+.. _Pragmatic Unicode: http://nedbatchelder.com/text/unipain.html
+
+Porting tips
+============
+
+Unicode literals
+----------------
+
+This step consists in:
+
+- Adding ``from __future__ import unicode_literals`` at the top of your Python
+ modules -- it's best to put it in each and every module, otherwise you'll
+ keep checking the top of your files to see which mode is in effect;
+- Removing the ``u`` prefix before unicode strings;
+- Adding a ``b`` prefix before bytestrings.
+
+Performing these changes systematically guarantees backwards compatibility.
+
+However, Django applications generally don't need bytestrings, since Django
+only exposes unicode interfaces to the programmer. Python 3 discourages using
+bytestrings, except for binary data or byte-oriented interfaces. Python 2
+makes bytestrings and unicode strings effectively interchangeable, as long as
+they only contain ASCII data. Take advantage of this to use unicode strings
+wherever possible and avoid the ``b`` prefixes.
+
+.. note::
+
+ Python 2's ``u`` prefix is a syntax error in Python 3.2 but it will be
+ allowed again in Python 3.3 thanks to :pep:`414`. Thus, this
+ transformation is optional if you target Python ≥ 3.3. It's still
+ recommended, per the "write Python 3 code" philosophy.
+
+String handling
+---------------
+
+Python 2's :class:`unicode` type was renamed :class:`str` in Python 3,
+:class:`str` was renamed :class:`bytes`, and :class:`basestring` disappeared.
+six_ provides :ref:`tools <string-handling-with-six>` to deal with these
+changes.
+
+Django also contains several string related classes and functions in the
+:mod:`django.utils.encoding` and :mod:`django.utils.safestring` modules. Their
+names used the words ``str``, which doesn't mean the same thing in Python 2
+and Python 3, and ``unicode``, which doesn't exist in Python 3. In order to
+avoid ambiguity and confusion these concepts were renamed ``bytes`` and
+``text``.
+
+Here are the name changes in :mod:`django.utils.encoding`:
+
+================== ==================
+Old name New name
+================== ==================
+``smart_str`` ``smart_bytes``
+``smart_unicode`` ``smart_text``
+``force_unicode`` ``force_text``
+================== ==================
+
+For backwards compatibility, the old names still work on Python 2. Under
+Python 3, ``smart_str`` is an alias for ``smart_text``.
+
+.. note::
+
+ :mod:`django.utils.encoding` was deeply refactored in Django 1.5 to
+ provide a more consistent API. Check its documentation for more
+ information.
+
+:mod:`django.utils.safestring` is mostly used via the
+:func:`~django.utils.safestring.mark_safe` and
+:func:`~django.utils.safestring.mark_for_escaping` functions, which didn't
+change. In case you're using the internals, here are the name changes:
+
+================== ==================
+Old name New name
+================== ==================
+``EscapeString`` ``EscapeBytes``
+``EscapeUnicode`` ``EscapeText``
+``SafeString`` ``SafeBytes``
+``SafeUnicode`` ``SafeText``
+================== ==================
+
+For backwards compatibility, the old names still work on Python 2. Under
+Python 3, ``EscapeString`` and ``SafeString`` are aliases for ``EscapeText``
+and ``SafeText`` respectively.
+
+:meth:`__str__` and :meth:`__unicode__` methods
+-----------------------------------------------
+
+In Python 2, the object model specifies :meth:`__str__` and
+:meth:`__unicode__` methods. If these methods exist, they must return
+:class:`str` (bytes) and :class:`unicode` (text) respectively.
+
+The ``print`` statement and the :func:`str` built-in call :meth:`__str__` to
+determine the human-readable representation of an object. The :func:`unicode`
+built-in calls :meth:`__unicode__` if it exists, and otherwise falls back to
+:meth:`__str__` and decodes the result with the system encoding. Conversely,
+the :class:`~django.db.models.Model` base class automatically derives
+:meth:`__str__` from :meth:`__unicode__` by encoding to UTF-8.
+
+In Python 3, there's simply :meth:`__str__`, which must return :class:`str`
+(text).
+
+(It is also possible to define :meth:`__bytes__`, but Django application have
+little use for that method, because they hardly ever deal with
+:class:`bytes`.)
+
+Django provides a simple way to define :meth:`__str__` and :meth:`__unicode__`
+methods that work on Python 2 and 3: you must define a :meth:`__str__` method
+returning text and to apply the
+:func:`~django.utils.encoding.python_2_unicode_compatible` decorator.
+
+On Python 3, the decorator is a no-op. On Python 2, it defines appropriate
+:meth:`__unicode__` and :meth:`__str__` methods (replacing the original
+:meth:`__str__` method in the process). Here's an example::
+
+ from __future__ import unicode_literals
+ from django.utils.encoding import python_2_unicode_compatible
+
+ @python_2_unicode_compatible
+ class MyClass(object):
+ def __str__(self):
+ return "Instance of my class"
+
+This technique is the best match for Django's porting philosophy.
+
+Finally, note that :meth:`__repr__` must return a :class:`str` on all versions
+of Python.
+
+:class:`dict` and :class:`dict`-like classes
+--------------------------------------------
+
+:meth:`dict.keys`, :meth:`dict.items` and :meth:`dict.values` return lists in
+Python 2 and iterators in Python 3. :class:`~django.http.QueryDict` and the
+:class:`dict`-like classes defined in :mod:`django.utils.datastructures`
+behave likewise in Python 3.
+
+six_ provides compatibility functions to work around this change:
+:func:`~six.iterkeys`, :func:`~six.iteritems`, and :func:`~six.itervalues`.
+Django's bundled version adds :func:`~django.utils.six.iterlists` for
+:class:`~django.utils.datastructures.MultiValueDict` and its subclasses.
+
+:class:`~django.http.HttpRequest` and :class:`~django.http.HttpResponse` objects
+--------------------------------------------------------------------------------
+
+According to :pep:`3333`:
+
+- headers are always :class:`str` objects,
+- input and output streams are always :class:`bytes` objects.
+
+Specifically, :attr:`HttpResponse.content <django.http.HttpResponse.content>`
+contains :class:`bytes`, which may become an issue if you compare it with a
+:class:`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
+response and a unicode string as arguments.
+
+Coding guidelines
+=================
+
+The following guidelines are enforced in Django's source code. They're also
+recommended for third-party application who follow the same porting strategy.
Syntax requirements
-===================
+-------------------
Unicode
--------
+~~~~~~~
In Python 3, all strings are considered Unicode by default. The ``unicode``
type from Python 2 is called ``str`` in Python 3, and ``str`` becomes
@@ -36,17 +224,25 @@ In order to enable the same behavior in Python 2, every module must import
my_string = "This is an unicode literal"
my_bytestring = b"This is a bytestring"
-If you need a byte string under Python 2 and a unicode string under Python 3,
-use the :func:`str` builtin::
+If you need a byte string literal under Python 2 and a unicode string literal
+under Python 3, use the :func:`str` builtin::
str('my string')
-Be cautious if you have to `slice bytestrings`_.
+In Python 3, there aren't any automatic conversions between :class:`str` and
+:class:`bytes`, and the :mod:`codecs` module became more strict.
+:meth:`str.decode` always returns :class:`bytes`, and :meth:`bytes.decode`
+always returns :class:`str`. As a consequence, the following pattern is
+sometimes necessary::
+
+ value = value.encode('ascii', 'ignore').decode('ascii')
+
+Be cautious if you have to `index bytestrings`_.
-.. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals
+.. _index bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals
Exceptions
-----------
+~~~~~~~~~~
When you capture exceptions, use the ``as`` keyword::
@@ -59,17 +255,64 @@ This older syntax was removed in Python 3::
try:
...
- except MyException, exc:
+ except MyException, exc: # Don't do that!
...
The syntax to reraise an exception with a different traceback also changed.
Use :func:`six.reraise`.
+Magic methods
+-------------
+
+Use the patterns below to handle magic methods renamed in Python 3.
+
+Iterators
+~~~~~~~~~
+
+::
+
+ class MyIterator(object):
+ def __iter__(self):
+ return self # implement some logic here
+
+ def __next__(self):
+ raise StopIteration # implement some logic here
+
+ next = __next__ # Python 2 compatibility
+
+Boolean evaluation
+~~~~~~~~~~~~~~~~~~
+
+::
+
+ class MyBoolean(object):
+
+ def __bool__(self):
+ return True # implement some logic here
+
+ __nonzero__ = __bool__ # Python 2 compatibility
+
+Division
+~~~~~~~~
+
+::
+
+ class MyDivisible(object):
+
+ def __truediv__(self, other):
+ return self / other # implement some logic here
+
+ __div__ = __truediv__ # Python 2 compatibility
+
+ def __itruediv__(self, other):
+ return self // other # implement some logic here
+
+ __idiv__ = __itruediv__ # Python 2 compatibility
.. module: django.utils.six
Writing compatible code with six
-================================
+--------------------------------
six_ is the canonical compatibility library for supporting Python 2 and 3 in
a single codebase. Read its documentation!
@@ -78,8 +321,10 @@ a single codebase. Read its documentation!
Here are the most common changes required to write compatible code.
-String types
-------------
+.. _string-handling-with-six:
+
+String handling
+~~~~~~~~~~~~~~~
The ``basestring`` and ``unicode`` types were removed in Python 3, and the
meaning of ``str`` changed. To test these types, use the following idioms::
@@ -92,7 +337,7 @@ Python ≥ 2.6 provides ``bytes`` as an alias for ``str``, so you don't need
:attr:`six.binary_type`.
``long``
---------
+~~~~~~~~
The ``long`` type no longer exists in Python 3. ``1L`` is a syntax error. Use
:data:`six.integer_types` check if a value is an integer or a long::
@@ -100,21 +345,27 @@ The ``long`` type no longer exists in Python 3. ``1L`` is a syntax error. Use
isinstance(myvalue, six.integer_types) # replacement for (int, long)
``xrange``
-----------
+~~~~~~~~~~
Import :func:`six.moves.xrange` wherever you use ``xrange``.
Moved modules
--------------
+~~~~~~~~~~~~~
Some modules were renamed in Python 3. The :mod:`django.utils.six.moves
<six.moves>` module provides a compatible location to import them.
-In addition to six' defaults, Django's version provides ``dummy_thread`` as
-``_dummy_thread``.
+The ``urllib``, ``urllib2`` and ``urlparse`` modules were reworked in depth
+and :mod:`django.utils.six.moves <six.moves>` doesn't handle them. Django
+explicitly tries both locations, as follows::
+
+ try:
+ from urllib.parse import urlparse, urlunparse
+ except ImportError: # Python 2
+ from urlparse import urlparse, urlunparse
PY3
----
+~~~
If you need different code in Python 2 and Python 3, check :data:`six.PY3`::
@@ -129,9 +380,9 @@ function.
.. module:: django.utils.six
Customizations of six
-=====================
+---------------------
-The version of six bundled with Django includes a few additional tools:
+The version of six bundled with Django includes one extra function:
.. function:: iterlists(MultiValueDict)
@@ -140,3 +391,6 @@ The version of six bundled with Django includes a few additional tools:
:meth:`~django.utils.datastructures.MultiValueDict.iterlists()` on Python
2 and :meth:`~django.utils.datastructures.MultiValueDict.lists()` on
Python 3.
+
+In addition to six' defaults moves, Django's version provides ``thread`` as
+``_thread`` and ``dummy_thread`` as ``_dummy_thread``.
diff --git a/docs/topics/templates.txt b/docs/topics/templates.txt
index 2fa6643975..af45a8d95b 100644
--- a/docs/topics/templates.txt
+++ b/docs/topics/templates.txt
@@ -102,7 +102,7 @@ Use a dot (``.``) to access attributes of a variable.
attempts to loop over a ``collections.defaultdict``::
{% for k, v in defaultdict.iteritems %}
- Do something with k and v here...
+ Do something with k and v here...
{% endfor %}
Because dictionary lookup happens first, that behavior kicks in and provides
@@ -116,6 +116,10 @@ If you use a variable that doesn't exist, the template system will insert
the value of the :setting:`TEMPLATE_STRING_IF_INVALID` setting, which is set
to ``''`` (the empty string) by default.
+Note that "bar" in a template expression like ``{{ foo.bar }}`` will be
+interpreted as a literal string and not using the value of the variable "bar",
+if one exists in the template context.
+
Filters
=======
diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
index 1f4c970d3e..c4c73733f5 100644
--- a/docs/topics/testing.txt
+++ b/docs/topics/testing.txt
@@ -2039,7 +2039,7 @@ out the `full reference`_ for more details.
self.selenium.find_element_by_xpath('//input[@value="Log in"]').click()
# Wait until the response is received
WebDriverWait(self.selenium, timeout).until(
- lambda driver: driver.find_element_by_tag_name('body'), timeout=10)
+ lambda driver: driver.find_element_by_tag_name('body'))
The tricky thing here is that there's really no such thing as a "page load,"
especially in modern Web apps that generate HTML dynamically after the