summaryrefslogtreecommitdiff
path: root/docs/topics
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
committerAndrew Godwin <andrew@aeracode.org>2012-09-05 09:39:03 -0400
commitb546e7eb633022ee1962570387f22fb2bcea46ed (patch)
treef87f4a2d68fb66afae39148fa35489930710b623 /docs/topics
parentcd583d6dbd222ae61331a6965b0e1fc86c974c50 (diff)
parentcff911f4ba3b3e6393c58da5131ce8b188a68f0c (diff)
Merge branch 'master' into schema-alteration
Diffstat (limited to 'docs/topics')
-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
17 files changed, 604 insertions, 254 deletions
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