Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merged recent Django trunk changes.

  • Loading branch information...
commit 0229209c844f06dfeb33b0b8eeec000c127695b6 2 parents 6494bf9 + 8599f64
@freakboy3742 freakboy3742 authored
Showing with 548 additions and 486 deletions.
  1. +1 −0  AUTHORS
  2. +16 −0 CONTRIBUTING.rst
  3. +1 −1  django/contrib/auth/admin.py
  4. +1 −1  django/contrib/auth/models.py
  5. +15 −0 django/contrib/auth/tests/signals.py
  6. +2 −0  django/contrib/gis/templates/gis/admin/openlayers.js
  7. +85 −49 django/contrib/gis/tests/geo3d/tests.py
  8. +2 −2 django/contrib/gis/tests/geoapp/tests.py
  9. +30 −0 django/contrib/gis/tests/layermap/tests.py
  10. +4 −4 django/contrib/gis/utils/layermapping.py
  11. +6 −0 django/contrib/sessions/tests.py
  12. +4 −1 django/core/files/storage.py
  13. +2 −2 django/core/handlers/base.py
  14. +2 −2 django/core/handlers/wsgi.py
  15. +2 −0  django/core/mail/backends/locmem.py
  16. +2 −2 django/db/backends/postgresql_psycopg2/base.py
  17. +2 −2 django/db/backends/util.py
  18. +5 −1 django/db/models/sql/compiler.py
  19. +3 −2 django/middleware/common.py
  20. +3 −2 django/middleware/csrf.py
  21. +2 −0  django/test/testcases.py
  22. +2 −2 django/utils/dateformat.py
  23. +15 −18 django/utils/html.py
  24. +2 −5 django/utils/numberformat.py
  25. +2 −2 django/views/decorators/http.py
  26. +3 −2 django/views/generic/base.py
  27. +3 −3 django/views/generic/dates.py
  28. +0 −2  docs/howto/custom-template-tags.txt
  29. +0 −4 docs/howto/error-reporting.txt
  30. +0 −2  docs/howto/static-files.txt
  31. +12 −0 docs/internals/committers.txt
  32. +1 −1  docs/internals/deprecation.txt
  33. +0 −2  docs/misc/api-stability.txt
  34. +8 −0 docs/ref/class-based-views/generic-date-based.txt
  35. +8 −4 docs/ref/class-based-views/mixins-date-based.txt
  36. +2 −19 docs/ref/contrib/admin/index.txt
  37. +0 −21 docs/ref/contrib/comments/example.txt
  38. +0 −4 docs/ref/contrib/comments/moderation.txt
  39. +0 −2  docs/ref/contrib/contenttypes.txt
  40. +0 −2  docs/ref/contrib/flatpages.txt
  41. +1 −1  docs/ref/contrib/gis/admin.txt
  42. +5 −4 docs/ref/contrib/gis/geos.txt
  43. +0 −2  docs/ref/contrib/gis/testing.txt
  44. +0 −7 docs/ref/contrib/localflavor.txt
  45. +0 −2  docs/ref/contrib/sitemaps.txt
  46. +2 −6 docs/ref/contrib/sites.txt
  47. +0 −2  docs/ref/contrib/staticfiles.txt
  48. +4 −24 docs/ref/django-admin.txt
  49. +3 −9 docs/ref/files/storage.txt
  50. +0 −2  docs/ref/forms/api.txt
  51. +0 −2  docs/ref/forms/fields.txt
  52. +0 −7 docs/ref/forms/widgets.txt
  53. +3 −2 docs/ref/models/fields.txt
  54. +5 −13 docs/ref/models/querysets.txt
  55. +0 −13 docs/ref/request-response.txt
  56. +2 −24 docs/ref/settings.txt
  57. +12 −13 docs/ref/signals.txt
  58. +0 −2  docs/ref/template-response.txt
  59. +0 −12 docs/ref/templates/api.txt
  60. +1 −13 docs/ref/templates/builtins.txt
  61. +22 −0 docs/releases/1.5.txt
  62. +0 −13 docs/topics/auth.txt
  63. +16 −23 docs/topics/cache.txt
  64. +0 −5 docs/topics/class-based-views/generic-display.txt
  65. +40 −0 docs/topics/class-based-views/generic-editing.txt
  66. +0 −2  docs/topics/class-based-views/index.txt
  67. +0 −2  docs/topics/class-based-views/mixins.txt
  68. +0 −3  docs/topics/db/queries.txt
  69. +2 −7 docs/topics/db/sql.txt
  70. +0 −5 docs/topics/db/transactions.txt
  71. +0 −5 docs/topics/email.txt
  72. +3 −13 docs/topics/forms/formsets.txt
  73. +0 −2  docs/topics/forms/media.txt
  74. +0 −2  docs/topics/http/middleware.txt
  75. +0 −2  docs/topics/http/shortcuts.txt
  76. +11 −8 docs/topics/http/urls.txt
  77. +0 −6 docs/topics/i18n/formatting.txt
  78. +0 −15 docs/topics/i18n/translation.txt
  79. +0 −2  docs/topics/logging.txt
  80. +0 −4 docs/topics/signals.txt
  81. +7 −16 docs/topics/testing.txt
  82. +3 −0  tests/regressiontests/defer_regress/models.py
  83. +15 −1 tests/regressiontests/defer_regress/tests.py
  84. +13 −4 tests/regressiontests/file_storage/tests.py
  85. +35 −15 tests/regressiontests/generic_views/dates.py
  86. +6 −5 tests/regressiontests/logging_tests/tests.py
  87. +5 −0 tests/regressiontests/mail/tests.py
  88. +13 −0 tests/regressiontests/model_permalink/models.py
  89. +9 −0 tests/regressiontests/model_permalink/tests.py
  90. +9 −0 tests/regressiontests/test_client_regress/tests.py
  91. +5 −0 tests/regressiontests/utils/dateformat.py
  92. +47 −0 tests/regressiontests/utils/numberformat.py
  93. +1 −0  tests/regressiontests/utils/tests.py
View
1  AUTHORS
@@ -33,6 +33,7 @@ The PRIMARY AUTHORS are (and/or have been):
* Florian Apolloner
* Jeremy Dunck
* Bryan Veloso
+ * Preston Holmes
More information on the main contributors to Django can be found in
docs/internals/committers.txt.
View
16 CONTRIBUTING.rst
@@ -0,0 +1,16 @@
+======================
+Contributing to Django
+======================
+
+As an open source project, Django welcomes contributions of many forms.
+
+Examples of contributions include:
+
+* Code patches
+* Documentation improvements
+* Bug reports and patch reviews
+
+Extensive contribution guidelines are available in the repository at
+``docs/internals/contributing/``, or online at:
+
+https://docs.djangoproject.com/en/dev/internals/contributing/
View
2  django/contrib/auth/admin.py
@@ -54,7 +54,7 @@ class UserAdmin(admin.ModelAdmin):
add_form = UserCreationForm
change_password_form = AdminPasswordChangeForm
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
- list_filter = ('is_staff', 'is_superuser', 'is_active')
+ list_filter = ('is_staff', 'is_superuser', 'is_active', 'groups')
search_fields = ('username', 'first_name', 'last_name', 'email')
ordering = ('username',)
filter_horizontal = ('user_permissions',)
View
2  django/contrib/auth/models.py
@@ -28,7 +28,7 @@ def update_last_login(sender, user, **kwargs):
the user logging in.
"""
user.last_login = timezone.now()
- user.save()
+ user.save(update_fields=['last_login'])
user_logged_in.connect(update_last_login)
View
15 django/contrib/auth/tests/signals.py
@@ -1,6 +1,8 @@
from django.contrib.auth import signals
+from django.contrib.auth.models import User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.test import TestCase
+from django.test.client import RequestFactory
from django.test.utils import override_settings
@@ -49,3 +51,16 @@ def test_logout(self):
self.client.get('/logout/next_page/')
self.assertEqual(len(self.logged_out), 1)
self.assertEqual(self.logged_out[0].username, 'testclient')
+
+ def test_update_last_login(self):
+ """Ensure that only `last_login` is updated in `update_last_login`"""
+ user = User.objects.get(pk=3)
+ old_last_login = user.last_login
+
+ user.username = "This username shouldn't get saved"
+ request = RequestFactory().get('/login')
+ signals.user_logged_in.send(sender=user.__class__, request=request,
+ user=user)
+ user = User.objects.get(pk=3)
+ self.assertEqual(user.username, 'staff')
+ self.assertNotEqual(user.last_login, old_last_login)
View
2  django/contrib/gis/templates/gis/admin/openlayers.js
@@ -109,10 +109,12 @@ OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.Sp
{% autoescape off %}{% for item in map_options.items %} '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %}
{% endfor %}{% endautoescape %} };{% endblock %}
// The admin map for this geometry field.
+ {% block map_creation %}
{{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
// Base Layer
{{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS("{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'{{ wms_options|safe }}});{% endblock %}
{{ module }}.map.addLayer({{ module }}.layers.base);
+ {% endblock %}
{% block extra_layers %}{% endblock %}
{% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
{{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}");
View
134 django/contrib/gis/tests/geo3d/tests.py
@@ -1,16 +1,17 @@
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
import os
import re
-from django.utils.unittest import TestCase
from django.contrib.gis.db.models import Union, Extent3D
from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
from django.contrib.gis.utils import LayerMapping, LayerMapError
+from django.test import TestCase
from .models import (City3D, Interstate2D, Interstate3D, InterstateProj2D,
InterstateProj3D, Point2D, Point3D, MultiPoint3D, Polygon2D, Polygon3D)
+
data_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'data'))
city_file = os.path.join(data_path, 'cities', 'cities.shp')
vrt_file = os.path.join(data_path, 'test_vrt', 'test_vrt.vrt')
@@ -46,12 +47,11 @@
# Bounding box polygon for inner-loop of Houston (in projected coordinate
# system 32140), with elevation values from the National Elevation Dataset
# (see above).
-bbox_wkt = 'POLYGON((941527.97 4225693.20,962596.48 4226349.75,963152.57 4209023.95,942051.75 4208366.38,941527.97 4225693.20))'
-bbox_z = (21.71, 13.21, 9.12, 16.40, 21.71)
-def gen_bbox():
- bbox_2d = GEOSGeometry(bbox_wkt, srid=32140)
- bbox_3d = Polygon(tuple((x, y, z) for (x, y), z in zip(bbox_2d[0].coords, bbox_z)), srid=32140)
- return bbox_2d, bbox_3d
+bbox_data = (
+ 'POLYGON((941527.97 4225693.20,962596.48 4226349.75,963152.57 4209023.95,942051.75 4208366.38,941527.97 4225693.20))',
+ (21.71, 13.21, 9.12, 16.40, 21.71)
+)
+
class Geo3DTest(TestCase):
"""
@@ -63,20 +63,7 @@ class Geo3DTest(TestCase):
http://postgis.refractions.net/documentation/manual-1.4/ch08.html#PostGIS_3D_Functions
"""
- def test01_3d(self):
- "Test the creation of 3D models."
- # 3D models for the rest of the tests will be populated in here.
- # For each 3D data set create model (and 2D version if necessary),
- # retrieve, and assert geometry is in 3D and contains the expected
- # 3D values.
- for name, pnt_data in city_data:
- x, y, z = pnt_data
- pnt = Point(x, y, z, srid=4326)
- City3D.objects.create(name=name, point=pnt)
- city = City3D.objects.get(name=name)
- self.assertTrue(city.point.hasz)
- self.assertEqual(z, city.point.z)
-
+ def _load_interstate_data(self):
# Interstate (2D / 3D and Geographic/Projected variants)
for name, line, exp_z in interstate_data:
line_3d = GEOSGeometry(line, srid=4269)
@@ -90,26 +77,51 @@ def test01_3d(self):
Interstate2D.objects.create(name=name, line=line_2d)
InterstateProj2D.objects.create(name=name, line=line_2d)
- # Retrieving and making sure it's 3D and has expected
- # Z values -- shouldn't change because of coordinate system.
+ def _load_city_data(self):
+ for name, pnt_data in city_data:
+ City3D.objects.create(name=name, point=Point(*pnt_data, srid=4326))
+
+ def _load_polygon_data(self):
+ bbox_wkt, bbox_z = bbox_data
+ bbox_2d = GEOSGeometry(bbox_wkt, srid=32140)
+ bbox_3d = Polygon(tuple((x, y, z) for (x, y), z in zip(bbox_2d[0].coords, bbox_z)), srid=32140)
+ Polygon2D.objects.create(name='2D BBox', poly=bbox_2d)
+ Polygon3D.objects.create(name='3D BBox', poly=bbox_3d)
+
+ def test_3d_hasz(self):
+ """
+ Make sure data is 3D and has expected Z values -- shouldn't change
+ because of coordinate system.
+ """
+ self._load_interstate_data()
+ for name, line, exp_z in interstate_data:
interstate = Interstate3D.objects.get(name=name)
interstate_proj = InterstateProj3D.objects.get(name=name)
for i in [interstate, interstate_proj]:
self.assertTrue(i.line.hasz)
self.assertEqual(exp_z, tuple(i.line.z))
- # Creating 3D Polygon.
- bbox2d, bbox3d = gen_bbox()
- Polygon2D.objects.create(name='2D BBox', poly=bbox2d)
- Polygon3D.objects.create(name='3D BBox', poly=bbox3d)
+ self._load_city_data()
+ for name, pnt_data in city_data:
+ city = City3D.objects.get(name=name)
+ z = pnt_data[2]
+ self.assertTrue(city.point.hasz)
+ self.assertEqual(z, city.point.z)
+
+ def test_3d_polygons(self):
+ """
+ Test the creation of polygon 3D models.
+ """
+ self._load_polygon_data()
p3d = Polygon3D.objects.get(name='3D BBox')
self.assertTrue(p3d.poly.hasz)
- self.assertEqual(bbox3d, p3d.poly)
-
- def test01a_3d_layermapping(self):
- "Testing LayerMapping on 3D models."
- from .models import Point2D, Point3D
+ self.assertIsInstance(p3d.poly, Polygon)
+ self.assertEqual(p3d.poly.srid, 32140)
+ def test_3d_layermapping(self):
+ """
+ Testing LayerMapping on 3D models.
+ """
point_mapping = {'point' : 'POINT'}
mpoint_mapping = {'mpoint' : 'MULTIPOINT'}
@@ -134,34 +146,46 @@ def test01a_3d_layermapping(self):
lm.save()
self.assertEqual(3, MultiPoint3D.objects.count())
- def test02a_kml(self):
- "Test GeoQuerySet.kml() with Z values."
+ def test_kml(self):
+ """
+ Test GeoQuerySet.kml() with Z values.
+ """
+ self._load_city_data()
h = City3D.objects.kml(precision=6).get(name='Houston')
# KML should be 3D.
# `SELECT ST_AsKML(point, 6) FROM geo3d_city3d WHERE name = 'Houston';`
ref_kml_regex = re.compile(r'^<Point><coordinates>-95.363\d+,29.763\d+,18</coordinates></Point>$')
self.assertTrue(ref_kml_regex.match(h.kml))
- def test02b_geojson(self):
- "Test GeoQuerySet.geojson() with Z values."
+ def test_geojson(self):
+ """
+ Test GeoQuerySet.geojson() with Z values.
+ """
+ self._load_city_data()
h = City3D.objects.geojson(precision=6).get(name='Houston')
# GeoJSON should be 3D
# `SELECT ST_AsGeoJSON(point, 6) FROM geo3d_city3d WHERE name='Houston';`
ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$')
self.assertTrue(ref_json_regex.match(h.geojson))
- def test03a_union(self):
- "Testing the Union aggregate of 3D models."
+ def test_union(self):
+ """
+ Testing the Union aggregate of 3D models.
+ """
# PostGIS query that returned the reference EWKT for this test:
# `SELECT ST_AsText(ST_Union(point)) FROM geo3d_city3d;`
+ self._load_city_data()
ref_ewkt = 'SRID=4326;MULTIPOINT(-123.305196 48.462611 15,-104.609252 38.255001 1433,-97.521157 34.464642 380,-96.801611 32.782057 147,-95.363151 29.763374 18,-95.23506 38.971823 251,-87.650175 41.850385 181,174.783117 -41.315268 14)'
ref_union = GEOSGeometry(ref_ewkt)
union = City3D.objects.aggregate(Union('point'))['point__union']
self.assertTrue(union.hasz)
self.assertEqual(ref_union, union)
- def test03b_extent(self):
- "Testing the Extent3D aggregate for 3D models."
+ def test_extent(self):
+ """
+ Testing the Extent3D aggregate for 3D models.
+ """
+ self._load_city_data()
# `SELECT ST_Extent3D(point) FROM geo3d_city3d;`
ref_extent3d = (-123.305196, -41.315268, 14,174.783117, 48.462611, 1433)
extent1 = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
@@ -174,8 +198,11 @@ def check_extent3d(extent3d, tol=6):
for e3d in [extent1, extent2]:
check_extent3d(e3d)
- def test04_perimeter(self):
- "Testing GeoQuerySet.perimeter() on 3D fields."
+ def test_perimeter(self):
+ """
+ Testing GeoQuerySet.perimeter() on 3D fields.
+ """
+ self._load_polygon_data()
# Reference query for values below:
# `SELECT ST_Perimeter3D(poly), ST_Perimeter2D(poly) FROM geo3d_polygon3d;`
ref_perim_3d = 76859.2620451
@@ -188,12 +215,15 @@ def test04_perimeter(self):
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
tol)
- def test05_length(self):
- "Testing GeoQuerySet.length() on 3D fields."
+ def test_length(self):
+ """
+ Testing GeoQuerySet.length() on 3D fields.
+ """
# ST_Length_Spheroid Z-aware, and thus does not need to use
# a separate function internally.
# `SELECT ST_Length_Spheroid(line, 'SPHEROID["GRS 1980",6378137,298.257222101]')
# FROM geo3d_interstate[2d|3d];`
+ self._load_interstate_data()
tol = 3
ref_length_2d = 4368.1721949481
ref_length_3d = 4368.62547052088
@@ -217,16 +247,22 @@ def test05_length(self):
InterstateProj3D.objects.length().get(name='I-45').length.m,
tol)
- def test06_scale(self):
- "Testing GeoQuerySet.scale() on Z values."
+ def test_scale(self):
+ """
+ Testing GeoQuerySet.scale() on Z values.
+ """
+ self._load_city_data()
# Mapping of City name to reference Z values.
zscales = (-3, 4, 23)
for zscale in zscales:
for city in City3D.objects.scale(1.0, 1.0, zscale):
self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z)
- def test07_translate(self):
- "Testing GeoQuerySet.translate() on Z values."
+ def test_translate(self):
+ """
+ Testing GeoQuerySet.translate() on Z values.
+ """
+ self._load_city_data()
ztranslations = (5.23, 23, -17)
for ztrans in ztranslations:
for city in City3D.objects.translate(0, 0, ztrans):
View
4 django/contrib/gis/tests/geoapp/tests.py
@@ -520,8 +520,8 @@ def test_gml(self):
if oracle:
# No precision parameter for Oracle :-/
gml_regex = re.compile(r'^<gml:Point srsName="SDO:4326" xmlns:gml="http://www.opengis.net/gml"><gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ </gml:coordinates></gml:Point>')
- elif spatialite:
- # Spatialite has extra colon in SrsName
+ elif spatialite and connection.ops.spatial_version < (3, 0, 0):
+ # Spatialite before 3.0 has extra colon in SrsName
gml_regex = re.compile(r'^<gml:Point SrsName="EPSG::4326"><gml:coordinates decimal="\." cs="," ts=" ">-104.609251\d+,38.255001</gml:coordinates></gml:Point>')
else:
gml_regex = re.compile(r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>-104\.60925\d+,38\.255001</gml:coordinates></gml:Point>')
View
30 django/contrib/gis/tests/layermap/tests.py
@@ -8,6 +8,7 @@
from django.contrib.gis.tests.utils import mysql
from django.contrib.gis.utils.layermapping import (LayerMapping, LayerMapError,
InvalidDecimal, MissingForeignKey)
+from django.db import router
from django.test import TestCase
from .models import (
@@ -26,6 +27,7 @@
NUMS = [1, 2, 1, 19, 1] # Number of polygons for each.
STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
+
class LayerMapTest(TestCase):
def test_init(self):
@@ -281,3 +283,31 @@ def test_textfield(self):
lm.save(silent=True, strict=True)
self.assertEqual(City.objects.count(), 3)
self.assertEqual(City.objects.all().order_by('name_txt')[0].name_txt, "Houston")
+
+
+class OtherRouter(object):
+ def db_for_read(self, model, **hints):
+ return 'other'
+
+ def db_for_write(self, model, **hints):
+ return self.db_for_read(model, **hints)
+
+ def allow_relation(self, obj1, obj2, **hints):
+ return None
+
+ def allow_syncdb(self, db, model):
+ return True
+
+
+class LayerMapRouterTest(TestCase):
+
+ def setUp(self):
+ self.old_routers = router.routers
+ router.routers = [OtherRouter()]
+
+ def tearDown(self):
+ router.routers = self.old_routers
+
+ def test_layermapping_default_db(self):
+ lm = LayerMapping(City, city_shp, city_mapping)
+ self.assertEqual(lm.using, 'other')
View
8 django/contrib/gis/utils/layermapping.py
@@ -9,7 +9,7 @@
import sys
from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist
-from django.db import connections, DEFAULT_DB_ALIAS
+from django.db import connections, router
from django.contrib.gis.db.models import GeometryField
from django.contrib.gis.gdal import (CoordTransform, DataSource,
OGRException, OGRGeometry, OGRGeomType, SpatialReference)
@@ -67,7 +67,7 @@ class LayerMapping(object):
def __init__(self, model, data, mapping, layer=0,
source_srs=None, encoding=None,
transaction_mode='commit_on_success',
- transform=True, unique=None, using=DEFAULT_DB_ALIAS):
+ transform=True, unique=None, using=None):
"""
A LayerMapping object is initialized using the given Model (not an instance),
a DataSource (or string path to an OGR-supported data file), and a mapping
@@ -81,8 +81,8 @@ def __init__(self, model, data, mapping, layer=0,
self.ds = data
self.layer = self.ds[layer]
- self.using = using
- self.spatial_backend = connections[using].ops
+ self.using = using if using is not None else router.db_for_write(model)
+ self.spatial_backend = connections[self.using].ops
# Setting the mapping & model attributes.
self.mapping = mapping
View
6 django/contrib/sessions/tests.py
@@ -12,6 +12,7 @@
from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession
from django.contrib.sessions.models import Session
from django.contrib.sessions.middleware import SessionMiddleware
+from django.core.cache import DEFAULT_CACHE_ALIAS
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.http import HttpResponse
from django.test import TestCase, RequestFactory
@@ -133,6 +134,9 @@ def test_clear(self):
self.assertTrue(self.session.modified)
def test_save(self):
+ if (hasattr(self.session, '_cache') and
+ 'DummyCache' in settings.CACHES[DEFAULT_CACHE_ALIAS]['BACKEND']):
+ raise unittest.SkipTest("Session saving tests require a real cache backend")
self.session.save()
self.assertTrue(self.session.exists(self.session.session_key))
@@ -296,6 +300,8 @@ class CacheDBSessionTests(SessionTestsMixin, TestCase):
backend = CacheDBSession
+ @unittest.skipIf('DummyCache' in settings.CACHES[DEFAULT_CACHE_ALIAS]['BACKEND'],
+ "Session saving tests require a real cache backend")
def test_exists_searches_cache_first(self):
self.session.save()
with self.assertNumQueries(0):
View
5 django/core/files/storage.py
@@ -192,7 +192,10 @@ def _save(self, name, content):
else:
# This fun binary flag incantation makes os.open throw an
# OSError if the file already exists before we open it.
- fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
+ flags = (os.O_WRONLY | os.O_CREAT | os.O_EXCL |
+ getattr(os, 'O_BINARY', 0))
+ # The current umask value is masked out by os.open!
+ fd = os.open(full_path, flags, 0o666)
try:
locks.lock(fd, locks.LOCK_EX)
_file = None
View
4 django/core/handlers/base.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+import logging
import sys
import types
@@ -7,10 +8,9 @@
from django.core import signals
from django.utils.encoding import force_text
from django.utils.importlib import import_module
-from django.utils.log import getLogger
from django.utils import six
-logger = getLogger('django.request')
+logger = logging.getLogger('django.request')
class BaseHandler(object):
View
4 django/core/handlers/wsgi.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
+import logging
import sys
from io import BytesIO
from threading import Lock
@@ -10,9 +11,8 @@
from django.core.urlresolvers import set_script_prefix
from django.utils import datastructures
from django.utils.encoding import force_str, force_text, iri_to_uri
-from django.utils.log import getLogger
-logger = getLogger('django.request')
+logger = logging.getLogger('django.request')
# See http://www.iana.org/assignments/http-status-codes
View
2  django/core/mail/backends/locmem.py
@@ -20,5 +20,7 @@ def __init__(self, *args, **kwargs):
def send_messages(self, messages):
"""Redirect messages to the dummy outbox"""
+ for message in messages: # .message() triggers header validation
+ message.message()
mail.outbox.extend(messages)
return len(messages)
View
4 django/db/backends/postgresql_psycopg2/base.py
@@ -3,6 +3,7 @@
Requires psycopg 2: http://initd.org/projects/psycopg2
"""
+import logging
import sys
from django.db import utils
@@ -14,7 +15,6 @@
from django.db.backends.postgresql_psycopg2.version import get_version
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
from django.utils.encoding import force_str
-from django.utils.log import getLogger
from django.utils.safestring import SafeText, SafeBytes
from django.utils import six
from django.utils.timezone import utc
@@ -33,7 +33,7 @@
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)
-logger = getLogger('django.db.backends')
+logger = logging.getLogger('django.db.backends')
def utc_tzinfo_factory(offset):
if offset != 0:
View
4 django/db/backends/util.py
@@ -3,15 +3,15 @@
import datetime
import decimal
import hashlib
+import logging
from time import time
from django.conf import settings
from django.utils.encoding import force_bytes
-from django.utils.log import getLogger
from django.utils.timezone import utc
-logger = getLogger('django.db.backends')
+logger = logging.getLogger('django.db.backends')
class CursorWrapper(object):
View
6 django/db/models/sql/compiler.py
@@ -609,8 +609,12 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
restricted = False
for f, model in opts.get_fields_with_model():
+ # The get_fields_with_model() returns None for fields that live
+ # in the field's local model. So, for those fields we want to use
+ # the f.model - that is the field's local model.
+ field_model = model or f.model
if not select_related_descend(f, restricted, requested,
- only_load.get(model or self.query.model)):
+ only_load.get(field_model)):
continue
# The "avoid" set is aliases we want to avoid just for this
# particular branch of the recursion. They aren't permanently
View
5 django/middleware/common.py
@@ -1,4 +1,5 @@
import hashlib
+import logging
import re
from django.conf import settings
@@ -6,9 +7,9 @@
from django.core.mail import mail_managers
from django.utils.http import urlquote
from django.core import urlresolvers
-from django.utils.log import getLogger
-logger = getLogger('django.request')
+
+logger = logging.getLogger('django.request')
class CommonMiddleware(object):
View
5 django/middleware/csrf.py
@@ -7,6 +7,7 @@
from __future__ import unicode_literals
import hashlib
+import logging
import re
import random
@@ -15,10 +16,10 @@
from django.utils.cache import patch_vary_headers
from django.utils.encoding import force_text
from django.utils.http import same_origin
-from django.utils.log import getLogger
from django.utils.crypto import constant_time_compare, get_random_string
-logger = getLogger('django.request')
+
+logger = logging.getLogger('django.request')
REASON_NO_REFERER = "Referer checking failed - no Referer."
REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
View
2  django/test/testcases.py
@@ -649,6 +649,7 @@ def assertContains(self, response, text, count=None, status_code=200,
self.assertEqual(response.status_code, status_code,
msg_prefix + "Couldn't retrieve content: Response code was %d"
" (expected %d)" % (response.status_code, status_code))
+ text = force_text(text, encoding=response._charset)
content = response.content.decode(response._charset)
if html:
content = assert_and_parse_html(self, content, None,
@@ -684,6 +685,7 @@ def assertNotContains(self, response, text, status_code=200,
self.assertEqual(response.status_code, status_code,
msg_prefix + "Couldn't retrieve content: Response code was %d"
" (expected %d)" % (response.status_code, status_code))
+ text = force_text(text, encoding=response._charset)
content = response.content.decode(response._charset)
if html:
content = assert_and_parse_html(self, content, None,
View
4 django/utils/dateformat.py
@@ -110,8 +110,8 @@ def s(self):
return '%02d' % self.data.second
def u(self):
- "Microseconds"
- return self.data.microsecond
+ "Microseconds; i.e. '000000' to '999999'"
+ return '%06d' %self.data.microsecond
class DateFormat(TimeFormat):
View
33 django/utils/html.py
@@ -42,29 +42,26 @@ def escape(text):
return mark_safe(force_text(text).replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;'))
escape = allow_lazy(escape, six.text_type)
-_base_js_escapes = (
- ('\\', '\\u005C'),
- ('\'', '\\u0027'),
- ('"', '\\u0022'),
- ('>', '\\u003E'),
- ('<', '\\u003C'),
- ('&', '\\u0026'),
- ('=', '\\u003D'),
- ('-', '\\u002D'),
- (';', '\\u003B'),
- ('\u2028', '\\u2028'),
- ('\u2029', '\\u2029')
-)
+_js_escapes = {
+ ord('\\'): '\\u005C',
+ ord('\''): '\\u0027',
+ ord('"'): '\\u0022',
+ ord('>'): '\\u003E',
+ ord('<'): '\\u003C',
+ ord('&'): '\\u0026',
+ ord('='): '\\u003D',
+ ord('-'): '\\u002D',
+ ord(';'): '\\u003B',
+ ord('\u2028'): '\\u2028',
+ ord('\u2029'): '\\u2029'
+}
# Escape every ASCII character with a value less than 32.
-_js_escapes = (_base_js_escapes +
- tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
+_js_escapes.update((ord('%c' % z), '\\u%04X' % z) for z in range(32))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
- for bad, good in _js_escapes:
- value = mark_safe(force_text(value).replace(bad, good))
- return value
+ return mark_safe(force_text(value).translate(_js_escapes))
escapejs = allow_lazy(escapejs, six.text_type)
def conditional_escape(text):
View
7 django/utils/numberformat.py
@@ -21,12 +21,10 @@ def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='',
if isinstance(number, int) and not use_grouping and not decimal_pos:
return mark_safe(six.text_type(number))
# sign
- if float(number) < 0:
- sign = '-'
- else:
- sign = ''
+ sign = ''
str_number = six.text_type(number)
if str_number[0] == '-':
+ sign = '-'
str_number = str_number[1:]
# decimal part
if '.' in str_number:
@@ -48,4 +46,3 @@ def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='',
int_part_gd += digit
int_part = int_part_gd[::-1]
return sign + int_part + dec_part
-
View
4 django/views/decorators/http.py
@@ -2,18 +2,18 @@
Decorators for views based on HTTP headers.
"""
+import logging
from calendar import timegm
from functools import wraps
from django.utils.decorators import decorator_from_middleware, available_attrs
from django.utils.http import http_date, parse_http_date_safe, parse_etags, quote_etag
-from django.utils.log import getLogger
from django.middleware.http import ConditionalGetMiddleware
from django.http import HttpResponseNotAllowed, HttpResponseNotModified, HttpResponse
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
-logger = getLogger('django.request')
+logger = logging.getLogger('django.request')
def require_http_methods(request_method_list):
View
5 django/views/generic/base.py
@@ -1,14 +1,15 @@
from __future__ import unicode_literals
+import logging
from functools import update_wrapper
+
from django import http
from django.core.exceptions import ImproperlyConfigured
from django.template.response import TemplateResponse
-from django.utils.log import getLogger
from django.utils.decorators import classonlymethod
from django.utils import six
-logger = getLogger('django.request')
+logger = logging.getLogger('django.request')
class ContextMixin(object):
View
6 django/views/generic/dates.py
@@ -377,7 +377,7 @@ def get_date_list_period(self):
"""
return self.date_list_period
- def get_date_list(self, queryset, date_type=None):
+ def get_date_list(self, queryset, date_type=None, ordering='ASC'):
"""
Get a date list by calling `queryset.dates()`, checking along the way
for empty lists that aren't allowed.
@@ -387,7 +387,7 @@ def get_date_list(self, queryset, date_type=None):
if date_type is None:
date_type = self.get_date_list_period()
- date_list = queryset.dates(date_field, date_type)[::-1]
+ date_list = queryset.dates(date_field, date_type, ordering)
if date_list is not None and not date_list and not allow_empty:
name = force_text(queryset.model._meta.verbose_name_plural)
raise Http404(_("No %(verbose_name_plural)s available") %
@@ -409,7 +409,7 @@ def get_dated_items(self):
Return (date_list, items, extra_context) for this request.
"""
qs = self.get_dated_queryset(ordering='-%s' % self.get_date_field())
- date_list = self.get_date_list(qs)
+ date_list = self.get_date_list(qs, ordering='DESC')
if not date_list:
qs = qs.none()
View
2  docs/howto/custom-template-tags.txt
@@ -760,8 +760,6 @@ A few things to note about the ``simple_tag`` helper function:
* If the argument was a template variable, our function is passed the
current value of the variable, not the variable itself.
-.. versionadded:: 1.3
-
If your template tag needs to access the current context, you can use the
``takes_context`` argument when registering your tag:
View
4 docs/howto/error-reporting.txt
@@ -44,8 +44,6 @@ setting.
.. seealso::
- .. versionadded:: 1.3
-
Server error emails are sent using the logging framework, so you can
customize this behavior by :doc:`customizing your logging configuration
</topics/logging>`.
@@ -99,8 +97,6 @@ The best way to disable this behavior is to set
.. seealso::
- .. versionadded:: 1.3
-
404 errors are logged using the logging framework. By default, these log
records are ignored, but you can use them for error reporting by writing a
handler and :doc:`configuring logging </topics/logging>` appropriately.
View
2  docs/howto/static-files.txt
@@ -2,8 +2,6 @@
Managing static files
=====================
-.. versionadded:: 1.3
-
Django developers mostly concern themselves with the dynamic parts of web
applications -- the views and templates that render anew for each request. But
web applications have other parts: the static files (images, CSS,
View
12 docs/internals/committers.txt
@@ -407,6 +407,18 @@ Jeremy Dunck
.. _vlogger: http://youtube.com/bryanveloso/
.. _shoutcaster: http://twitch.tv/vlogalonstar/
+`Preston Holmes`_
+ Preston is a recovering neuroscientist who originally discovered Django as
+ part of a sweeping move to Python from a grab bag of half a dozen
+ languages. He was drawn to Django's balance of practical batteries included
+ philosophy, care and thought in code design, and strong open source
+ community. In addition to his current job in private progressive education,
+ Preston contributes some developer time to local non-profits.
+
+ Preston lives with his family and animal menagerie in Santa Barbara, CA, USA.
+
+.. _Preston Holmes: http://www.ptone.com/
+
Specialists
-----------
View
2  docs/internals/deprecation.txt
@@ -134,7 +134,7 @@ these changes.
* The function-based generic view modules will be removed in favor of their
class-based equivalents, outlined :doc:`here
- </topics/class-based-views/index>`:
+ </topics/class-based-views/index>`.
* The :class:`~django.core.servers.basehttp.AdminMediaHandler` will be
removed. In its place use
View
2  docs/misc/api-stability.txt
@@ -155,8 +155,6 @@ Certain APIs are explicitly marked as "internal" in a couple of ways:
Local flavors
-------------
-.. versionchanged:: 1.3
-
:mod:`django.contrib.localflavor` contains assorted pieces of code
that are useful for particular countries or cultures. This data is
local in nature, and is subject to change on timelines that will
View
8 docs/ref/class-based-views/generic-date-based.txt
@@ -87,16 +87,24 @@ YearArchiveView
* ``year``: A :class:`~datetime.date` object
representing the given year.
+ .. versionchanged:: 1.5
+
+ Previously, this returned a string.
+
* ``next_year``: A :class:`~datetime.date` object
representing the first day of the next year, according to
:attr:`~BaseDateListView.allow_empty` and
:attr:`~DateMixin.allow_future`.
+ .. versionadded:: 1.5
+
* ``previous_year``: A :class:`~datetime.date` object
representing the first day of the previous year, according to
:attr:`~BaseDateListView.allow_empty` and
:attr:`~DateMixin.allow_future`.
+ .. versionadded:: 1.5
+
**Notes**
* Uses a default ``template_name_suffix`` of ``_archive_year``.
View
12 docs/ref/class-based-views/mixins-date-based.txt
@@ -318,12 +318,16 @@ BaseDateListView
Returns the aggregation period for ``date_list``. Returns
:attr:`~BaseDateListView.date_list_period` by default.
- .. method:: get_date_list(queryset, date_type=None)
+ .. method:: get_date_list(queryset, date_type=None, ordering='ASC')
Returns the list of dates of type ``date_type`` for which ``queryset``
contains entries. For example, ``get_date_list(qs, 'year')`` will
return the list of years for which ``qs`` has entries. If
``date_type`` isn't provided, the result of
- :meth:`BaseDateListView.get_date_list_period` is used. See
- :meth:`~django.db.models.query.QuerySet.dates()` for the ways that the
- ``date_type`` argument can be used.
+ :meth:`~BaseDateListView.get_date_list_period` is used. ``date_type``
+ and ``ordering`` are simply passed to
+ :meth:`QuerySet.dates()<django.db.models.query.QuerySet.dates>`.
+
+ .. versionchanged:: 1.5
+ The ``ordering`` parameter was added, and the default order was
+ changed to ascending.
View
21 docs/ref/contrib/admin/index.txt
@@ -129,8 +129,6 @@ subclass::
date_hierarchy = 'pub_date'
- .. versionadded:: 1.3
-
This will intelligently populate itself based on available data,
e.g. if all the dates are in one month, it'll show the day-level
drill-down only.
@@ -576,8 +574,6 @@ subclass::
class PersonAdmin(ModelAdmin):
list_filter = ('is_staff', 'company')
- .. versionadded:: 1.3
-
Field names in ``list_filter`` can also span relations
using the ``__`` lookup, for example::
@@ -748,8 +744,6 @@ subclass::
.. attribute:: ModelAdmin.paginator
- .. versionadded:: 1.3
-
The paginator class to be used for pagination. By default,
:class:`django.core.paginator.Paginator` is used. If the custom paginator
class doesn't have the same constructor interface as
@@ -966,8 +960,6 @@ templates used by the :class:`ModelAdmin` views:
.. method:: ModelAdmin.delete_model(self, request, obj)
- .. versionadded:: 1.3
-
The ``delete_model`` method is given the ``HttpRequest`` and a model
instance. Use this method to do pre- or post-delete operations.
@@ -1213,8 +1205,6 @@ templates used by the :class:`ModelAdmin` views:
.. method:: ModelAdmin.get_paginator(queryset, per_page, orphans=0, allow_empty_first_page=True)
- .. versionadded:: 1.3
-
Returns an instance of the paginator to use for this view. By default,
instantiates an instance of :attr:`paginator`.
@@ -1295,8 +1285,6 @@ on your ``ModelAdmin``::
}
js = ("my_code.js",)
-.. versionchanged:: 1.3
-
The :doc:`staticfiles app </ref/contrib/staticfiles>` prepends
:setting:`STATIC_URL` (or :setting:`MEDIA_URL` if :setting:`STATIC_URL` is
``None``) to any media paths. The same rules apply as :ref:`regular media
@@ -1394,18 +1382,15 @@ adds some of its own (the shared features are actually defined in the
- :attr:`~ModelAdmin.exclude`
- :attr:`~ModelAdmin.filter_horizontal`
- :attr:`~ModelAdmin.filter_vertical`
+- :attr:`~ModelAdmin.ordering`
- :attr:`~ModelAdmin.prepopulated_fields`
+- :meth:`~ModelAdmin.queryset`
- :attr:`~ModelAdmin.radio_fields`
- :attr:`~ModelAdmin.readonly_fields`
- :attr:`~InlineModelAdmin.raw_id_fields`
- :meth:`~ModelAdmin.formfield_for_foreignkey`
- :meth:`~ModelAdmin.formfield_for_manytomany`
-.. versionadded:: 1.3
-
-- :attr:`~ModelAdmin.ordering`
-- :meth:`~ModelAdmin.queryset`
-
.. versionadded:: 1.4
- :meth:`~ModelAdmin.has_add_permission`
@@ -1813,8 +1798,6 @@ Templates can override or extend base admin templates as described in
.. attribute:: AdminSite.login_form
- .. versionadded:: 1.3
-
Subclass of :class:`~django.contrib.auth.forms.AuthenticationForm` that
will be used by the admin site login view.
View
21 docs/ref/contrib/comments/example.txt
@@ -152,27 +152,6 @@ enable it in your project's ``urls.py``:
Now you should have the latest comment feeds being served off ``/feeds/latest/``.
-.. versionchanged:: 1.3
-
-Prior to Django 1.3, the LatestCommentFeed was deployed using the
-syndication feed view:
-
-.. code-block:: python
-
- from django.conf.urls import patterns
- from django.contrib.comments.feeds import LatestCommentFeed
-
- feeds = {
- 'latest': LatestCommentFeed,
- }
-
- urlpatterns = patterns('',
- # ...
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
- {'feed_dict': feeds}),
- # ...
- )
-
Moderation
==========
View
4 docs/ref/contrib/comments/moderation.txt
@@ -136,10 +136,6 @@ Simply subclassing :class:`CommentModerator` and changing the values of these
options will automatically enable the various moderation methods for any
models registered using the subclass.
-.. versionchanged:: 1.3
-
-``moderate_after`` and ``close_after`` now accept 0 as a valid value.
-
Adding custom moderation methods
--------------------------------
View
2  docs/ref/contrib/contenttypes.txt
@@ -423,8 +423,6 @@ pointing at it will be deleted as well. In the example above, this means that
if a ``Bookmark`` object were deleted, any ``TaggedItem`` objects pointing at
it would be deleted at the same time.
-.. versionadded:: 1.3
-
Unlike :class:`~django.db.models.ForeignKey`,
:class:`~django.contrib.contenttypes.generic.GenericForeignKey` does not accept
an :attr:`~django.db.models.ForeignKey.on_delete` argument to customize this
View
2  docs/ref/contrib/flatpages.txt
@@ -239,8 +239,6 @@ template.
Getting a list of :class:`~django.contrib.flatpages.models.FlatPage` objects in your templates
==============================================================================================
-.. versionadded:: 1.3
-
The flatpages app provides a template tag that allows you to iterate
over all of the available flatpages on the :ref:`current site
<hooking-into-current-site-from-views>`.
View
2  docs/ref/contrib/gis/admin.txt
@@ -45,7 +45,7 @@ GeoDjango's admin site
.. attribute:: openlayers_url
Link to the URL of the OpenLayers JavaScript. Defaults to
- ``'http://openlayers.org/api/2.8/OpenLayers.js'``.
+ ``'http://openlayers.org/api/2.11/OpenLayers.js'``.
.. attribute:: modifiable
View
9 docs/ref/contrib/gis/geos.txt
@@ -163,6 +163,11 @@ WKB / EWKB ``buffer``
GeoJSON ``str`` or ``unicode``
============= ======================
+.. note::
+
+ The new 3D/4D WKT notation with an intermediary Z or M (like
+ ``POINT Z (3, 4, 5)``) is only supported with GEOS 3.3.0 or later.
+
Properties
~~~~~~~~~~
@@ -232,8 +237,6 @@ Returns a boolean indicating whether the geometry is valid.
.. attribute:: GEOSGeometry.valid_reason
-.. versionadded:: 1.3
-
Returns a string describing the reason why a geometry is invalid.
.. attribute:: GEOSGeometry.srid
@@ -530,8 +533,6 @@ corresponding to the SRID of the geometry or ``None``.
.. method:: GEOSGeometry.transform(ct, clone=False)
-.. versionchanged:: 1.3
-
Transforms the geometry according to the given coordinate transformation paramter
(``ct``), which may be an integer SRID, spatial reference WKT string,
a PROJ.4 string, a :class:`~django.contrib.gis.gdal.SpatialReference` object, or a
View
2  docs/ref/contrib/gis/testing.txt
@@ -134,8 +134,6 @@ your settings::
GeoDjango tests
===============
-.. versionchanged:: 1.3
-
GeoDjango's test suite may be run in one of two ways, either by itself or
with the rest of :ref:`Django's unit tests <running-unit-tests>`.
View
7 docs/ref/contrib/localflavor.txt
@@ -267,8 +267,6 @@ Austria (``at``)
Belgium (``be``)
================
-.. versionadded:: 1.3
-
.. class:: be.forms.BEPhoneNumberField
A form field that validates input as a Belgium phone number, with one of
@@ -658,11 +656,6 @@ Indonesia (``id``)
A ``Select`` widget that uses a list of Indonesian provinces as its choices.
-.. versionchanged:: 1.3
- The province "Nanggroe Aceh Darussalam (NAD)" has been removed
- from the province list in favor of the new official designation
- "Aceh (ACE)".
-
.. class:: id.forms.IDPhoneNumberField
A form field that validates input as an Indonesian telephone number.
View
2  docs/ref/contrib/sitemaps.txt
@@ -330,8 +330,6 @@ with a caching decorator -- you must name your sitemap view and pass
Template customization
======================
-.. versionadded:: 1.3
-
If you wish to use a different template for each sitemap or sitemap index
available on your site, you may specify it by passing a ``template_name``
parameter to the ``sitemap`` and ``index`` views via the URLconf::
View
8 docs/ref/contrib/sites.txt
@@ -159,8 +159,6 @@ the :class:`~django.contrib.sites.models.Site` model's manager has a
else:
# Do something else.
-.. versionchanged:: 1.3
-
For code which relies on getting the current domain but cannot be certain
that the sites framework will be installed for any given project, there is a
utility function :func:`~django.contrib.sites.models.get_current_site` that
@@ -169,12 +167,10 @@ the sites framework is installed) or a RequestSite instance (if it is not).
This allows loose coupling with the sites framework and provides a usable
fallback for cases where it is not installed.
-.. versionadded:: 1.3
-
.. function:: get_current_site(request)
Checks if contrib.sites is installed and returns either the current
- :class:`~django.contrib.sites.models.Site` object or a
+ :class:`~django.contrib.sites.models.Site` object or a
:class:`~django.contrib.sites.models.RequestSite` object based on
the request.
@@ -437,7 +433,7 @@ fallback when the database-backed sites framework is not available.
Sets the ``name`` and ``domain`` attributes to the value of
:meth:`~django.http.HttpRequest.get_host`.
-
+
A :class:`~django.contrib.sites.models.RequestSite` object has a similar
interface to a normal :class:`~django.contrib.sites.models.Site` object, except
View
2  docs/ref/contrib/staticfiles.txt
@@ -5,8 +5,6 @@ The staticfiles app
.. module:: django.contrib.staticfiles
:synopsis: An app for handling static files.
-.. versionadded:: 1.3
-
``django.contrib.staticfiles`` collects static files from each of your
applications (and any other places you specify) into a single location that
can easily be served in production.
View
28 docs/ref/django-admin.txt
@@ -176,8 +176,6 @@ records to dump. If you're using a :ref:`custom manager <custom-managers>` as
the default manager and it filters some of the available records, not all of the
objects will be dumped.
-.. versionadded:: 1.3
-
The :djadminopt:`--all` option may be provided to specify that
``dumpdata`` should use Django's base manager, dumping records which
might otherwise be filtered or modified by a custom manager.
@@ -195,18 +193,10 @@ easy for humans to read, so you can use the ``--indent`` option to
pretty-print the output with a number of indentation spaces.
The :djadminopt:`--exclude` option may be provided to prevent specific
-applications from being dumped.
-
-.. versionadded:: 1.3
-
-The :djadminopt:`--exclude` option may also be provided to prevent specific
-models (specified as in the form of ``appname.ModelName``) from being dumped.
-
-In addition to specifying application names, you can provide a list of
-individual models, in the form of ``appname.Model``. If you specify a model
-name to ``dumpdata``, the dumped output will be restricted to that model,
-rather than the entire application. You can also mix application names and
-model names.
+applications or models (specified as in the form of ``appname.ModelName``) from
+being dumped. If you specify a model name to ``dumpdata``, the dumped output
+will be restricted to that model, rather than the entire application. You can
+also mix application names and model names.
The :djadminopt:`--database` option can be used to specify the database
from which data will be dumped.
@@ -463,8 +453,6 @@ Use the ``--no-default-ignore`` option to disable the default values of
.. django-admin-option:: --no-wrap
-.. versionadded:: 1.3
-
Use the ``--no-wrap`` option to disable breaking long message lines into
several lines in language files.
@@ -640,15 +628,11 @@ machines on your network. To make your development server viewable to other
machines on the network, use its own IP address (e.g. ``192.168.2.1``) or
``0.0.0.0`` or ``::`` (with IPv6 enabled).
-.. versionchanged:: 1.3
-
You can provide an IPv6 address surrounded by brackets
(e.g. ``[200a::1]:8000``). This will automatically enable IPv6 support.
A hostname containing ASCII-only characters can also be used.
-.. versionchanged:: 1.3
-
If the :doc:`staticfiles</ref/contrib/staticfiles>` contrib app is enabled
(default in new projects) the :djadmin:`runserver` command will be overriden
with an own :djadmin:`runserver<staticfiles-runserver>` command.
@@ -674,8 +658,6 @@ development server.
.. django-admin-option:: --ipv6, -6
-.. versionadded:: 1.3
-
Use the ``--ipv6`` (or shorter ``-6``) option to tell Django to use IPv6 for
the development server. This changes the default IP address from
``127.0.0.1`` to ``::1``.
@@ -1113,8 +1095,6 @@ To run on 1.2.3.4:7000 with a ``test`` fixture::
django-admin.py testserver --addrport 1.2.3.4:7000 test
-.. versionadded:: 1.3
-
The :djadminopt:`--noinput` option may be provided to suppress all user
prompts.
View
12 docs/ref/files/storage.txt
@@ -18,7 +18,7 @@ Django provides two convenient ways to access the current storage class:
.. function:: get_storage_class([import_path=None])
Returns a class or module which implements the storage API.
-
+
When called without the ``import_path`` parameter ``get_storage_class``
will return the current default storage system as defined by
:setting:`DEFAULT_FILE_STORAGE`. If ``import_path`` is provided,
@@ -35,9 +35,9 @@ The FileSystemStorage Class
basic file storage on a local filesystem. It inherits from
:class:`~django.core.files.storage.Storage` and provides implementations
for all the public methods thereof.
-
+
.. note::
-
+
The :class:`FileSystemStorage.delete` method will not raise
raise an exception if the given file name does not exist.
@@ -53,16 +53,12 @@ The Storage Class
.. method:: accessed_time(name)
- .. versionadded:: 1.3
-
Returns a ``datetime`` object containing the last accessed time of the
file. For storage systems that aren't able to return the last accessed
time this will raise ``NotImplementedError`` instead.
.. method:: created_time(name)
- .. versionadded:: 1.3
-
Returns a ``datetime`` object containing the creation time of the file.
For storage systems that aren't able to return the creation time this
will raise ``NotImplementedError`` instead.
@@ -100,8 +96,6 @@ The Storage Class
.. method:: modified_time(name)
- .. versionadded:: 1.3
-
Returns a ``datetime`` object containing the last modified time. For
storage systems that aren't able to return the last modified time, this
will raise ``NotImplementedError`` instead.
View
2  docs/ref/forms/api.txt
@@ -658,8 +658,6 @@ those classes as an argument::
.. method:: BoundField.value()
- .. versionadded:: 1.3
-
Use this method to render the raw value of this field as it would be rendered
by a ``Widget``::
View
2  docs/ref/forms/fields.txt
@@ -704,8 +704,6 @@ For each field, we describe the default widget used if you don't specify
``TypedMultipleChoiceField``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. versionadded:: 1.3
-
.. class:: TypedMultipleChoiceField(**kwargs)
Just like a :class:`MultipleChoiceField`, except :class:`TypedMultipleChoiceField`
View
7 docs/ref/forms/widgets.txt
@@ -294,11 +294,6 @@ These widgets make use of the HTML elements ``input`` and ``textarea``.
Determines whether the widget will have a value filled in when the
form is re-displayed after a validation error (default is ``False``).
- .. versionchanged:: 1.3
- The default value for
- :attr:`~PasswordInput.render_value` was
- changed from ``True`` to ``False``
-
``HiddenInput``
~~~~~~~~~~~~~~~
@@ -532,8 +527,6 @@ File upload widgets
.. class:: ClearableFileInput
- .. versionadded:: 1.3
-
File upload input: ``<input type='file' ...>``, with an additional checkbox
input to clear the field's value, if the field is not required and has
initial data.
View
5 docs/ref/models/fields.txt
@@ -1023,8 +1023,6 @@ define the details of how the relation works.
The field on the related object that the relation is to. By default, Django
uses the primary key of the related object.
-.. versionadded:: 1.3
-
.. attribute:: ForeignKey.on_delete
When an object referenced by a :class:`ForeignKey` is deleted, Django by
@@ -1081,6 +1079,9 @@ the model is related. This works exactly the same as it does for
:class:`ForeignKey`, including all the options regarding :ref:`recursive
<recursive-relationships>` and :ref:`lazy <lazy-relationships>` relationships.
+Related objects can be added, removed, or created with the field's
+:class:`~django.db.models.fields.related.RelatedManager`.
+
Database Representation
~~~~~~~~~~~~~~~~~~~~~~~
View
18 docs/ref/models/querysets.txt
@@ -505,15 +505,8 @@ followed (optionally) by any output-affecting methods (such as ``values()``),
but it doesn't really matter. This is your chance to really flaunt your
individualism.
-.. versionchanged:: 1.3
-
-The ``values()`` method previously did not return anything for
-:class:`~django.db.models.ManyToManyField` attributes and would raise an error
-if you tried to pass this type of field to it.
-
-This restriction has been lifted, and you can now also refer to fields on
-related models with reverse relations through ``OneToOneField``, ``ForeignKey``
-and ``ManyToManyField`` attributes::
+You can also refer to fields on related models with reverse relations through
+``OneToOneField``, ``ForeignKey`` and ``ManyToManyField`` attributes::
Blog.objects.values('name', 'entry__headline')
[{'name': 'My blog', 'entry__headline': 'An entry'},
@@ -1664,10 +1657,9 @@ For example::
# This will delete all Blogs and all of their Entry objects.
blogs.delete()
-.. versionadded:: 1.3
- This cascade behavior is customizable via the
- :attr:`~django.db.models.ForeignKey.on_delete` argument to the
- :class:`~django.db.models.ForeignKey`.
+This cascade behavior is customizable via the
+:attr:`~django.db.models.ForeignKey.on_delete` argument to the
+:class:`~django.db.models.ForeignKey`.
The ``delete()`` method does a bulk delete and does not call any ``delete()``
methods on your models. It does, however, emit the
View
13 docs/ref/request-response.txt
@@ -42,8 +42,6 @@ All attributes should be considered read-only, unless stated otherwise below.
data in different ways than conventional HTML forms: binary images,
XML payload etc. For processing conventional form data, use ``HttpRequest.POST``.
- .. versionadded:: 1.3
-
You can also read from an HttpRequest using a file-like interface. See
:meth:`HttpRequest.read()`.
@@ -305,8 +303,6 @@ Methods
.. method:: HttpRequest.xreadlines()
.. method:: HttpRequest.__iter__()
- .. versionadded:: 1.3
-
Methods implementing a file-like interface for reading from an
HttpRequest instance. This makes it possible to consume an incoming
request in a streaming fashion. A common use-case would be to process a
@@ -509,9 +505,6 @@ In addition, ``QueryDict`` has the following methods:
>>> q.urlencode()
'a=2&b=3&b=5'
- .. versionchanged:: 1.3
- The ``safe`` parameter was added.
-
Optionally, urlencode can be passed characters which
do not require encoding. For example::
@@ -648,12 +641,6 @@ Methods
.. method:: HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True)
- .. versionchanged:: 1.3
-
- The possibility of specifying a ``datetime.datetime`` object in
- ``expires``, and the auto-calculation of ``max_age`` in such case
- was added. The ``httponly`` argument was also added.
-
.. versionchanged:: 1.4
The default value for httponly was changed from ``False`` to ``True``.
View
26 docs/ref/settings.txt
@@ -124,8 +124,6 @@ The model to use to represent a User. See :ref:`auth-custom-user`.
CACHES
------
-.. versionadded:: 1.3
-
Default::
{
@@ -166,12 +164,6 @@ backend class (i.e. ``mypackage.backends.whatever.WhateverCache``).
Writing a whole new cache backend from scratch is left as an exercise
to the reader; see the other backends for examples.
-.. note::
- Prior to Django 1.3, you could use a URI based version of the backend
- name to reference the built-in cache backends (e.g., you could use
- ``'db://tablename'`` to refer to the database backend). This format has
- been deprecated, and will be removed in Django 1.5.
-
.. setting:: CACHES-KEY_FUNCTION
KEY_FUNCTION
@@ -533,8 +525,6 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details).
TEST_DEPENDENCIES
~~~~~~~~~~~~~~~~~
-.. versionadded:: 1.3
-
Default: ``['default']``, for all databases other than ``default``,
which has no dependencies.
@@ -1261,8 +1251,6 @@ the ``locale`` directory (i.e. ``'/path/to/locale'``).
LOGGING
-------
-.. versionadded:: 1.3
-
Default: A logging configuration dictionary.
A data structure containing configuration information. The contents of
@@ -1277,8 +1265,6 @@ email log handler; all other log messages are given to a NullHandler.
LOGGING_CONFIG
--------------
-.. versionadded:: 1.3
-
Default: ``'django.utils.log.dictConfig'``
A path to a callable that will be used to configure logging in the
@@ -1370,13 +1356,11 @@ MEDIA_URL
Default: ``''`` (Empty string)
URL that handles the media served from :setting:`MEDIA_ROOT`, used
-for :doc:`managing stored files </topics/files>`.
+for :doc:`managing stored files </topics/files>`. It must end in a slash if set
+to a non-empty value.
Example: ``"http://media.example.com/"``
-.. versionchanged:: 1.3
- It must end in a slash if set to a non-empty value.
-
MESSAGE_LEVEL
-------------
@@ -1895,10 +1879,6 @@ A tuple of callables that are used to populate the context in ``RequestContext``
These callables take a request object as their argument and return a dictionary
of items to be merged into the context.
-.. versionadded:: 1.3
- The ``django.core.context_processors.static`` context processor
- was added in this release.
-
.. versionadded:: 1.4
The ``django.core.context_processors.tz`` context processor
was added in this release.
@@ -2159,8 +2139,6 @@ See also :setting:`TIME_ZONE`, :setting:`USE_I18N` and :setting:`USE_L10N`.
USE_X_FORWARDED_HOST
--------------------
-.. versionadded:: 1.3.1
-
Default: ``False``
A boolean that specifies whether to use the X-Forwarded-Host header in
View
25 docs/ref/signals.txt
@@ -46,7 +46,7 @@ pre_init
.. ^^^^^^^ this :module: hack keeps Sphinx from prepending the module.
-Whenever you instantiate a Django model,, this signal is sent at the beginning
+Whenever you instantiate a Django model, this signal is sent at the beginning
of the model's :meth:`~django.db.models.Model.__init__` method.
Arguments sent with this signal:
@@ -118,8 +118,6 @@ Arguments sent with this signal:
records in the database as the database might not be in a
consistent state yet.
-.. versionadded:: 1.3
-
``using``
The database alias being used.
@@ -155,8 +153,6 @@ Arguments sent with this signal:
records in the database as the database might not be in a
consistent state yet.
-.. versionadded:: 1.3
-
``using``
The database alias being used.
@@ -183,8 +179,6 @@ Arguments sent with this signal:
``instance``
The actual instance being deleted.
-.. versionadded:: 1.3
-
``using``
The database alias being used.
@@ -209,8 +203,6 @@ Arguments sent with this signal:
Note that the object will no longer be in the database, so be very
careful what you do with this instance.
-.. versionadded:: 1.3
-
``using``
The database alias being used.
@@ -271,8 +263,6 @@ Arguments sent with this signal:
For the ``pre_clear`` and ``post_clear`` actions, this is ``None``.
-.. versionadded:: 1.3
-
``using``
The database alias being used.
@@ -287,13 +277,22 @@ like this::
# ...
toppings = models.ManyToManyField(Topping)
-If we would do something like this:
+If we connected a handler like this::
+
+ def toppings_changed(sender, **kwargs):
+ # Do something
+ pass
+
+ m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)
+
+and then did something like this::
>>> p = Pizza.object.create(...)
>>> t = Topping.objects.create(...)
>>> p.toppings.add(t)
-the arguments sent to a :data:`m2m_changed` handler would be:
+the arguments sent to a :data:`m2m_changed` handler (``topppings_changed`` in
+the example above) would be:
============== ============================================================
Argument Value
View
2  docs/ref/template-response.txt
@@ -2,8 +2,6 @@
TemplateResponse and SimpleTemplateResponse
===========================================
-.. versionadded:: 1.3
-
.. module:: django.template.response
:synopsis: Classes dealing with lazy-rendered HTTP responses.
View
12 docs/ref/templates/api.txt
@@ -160,11 +160,6 @@ it. Example::
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
-.. versionchanged:: 1.3
- Previously, only variables that originated with an attribute lookup would
- be called by the template system. This change was made for consistency
- across lookup types.
-
Callable variables are slightly more complex than variables which only require
straight lookups. Here are some things to keep in mind:
@@ -448,11 +443,6 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
``django.contrib.auth.context_processors.PermWrapper``, representing the
permissions that the currently logged-in user has.
-.. versionchanged:: 1.3
- Prior to version 1.3, ``PermWrapper`` was located in
- ``django.contrib.auth.context_processors``.
-
-
django.core.context_processors.debug
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -491,8 +481,6 @@ django.core.context_processors.static
.. function:: django.core.context_processors.static
-.. versionadded:: 1.3
-
If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
``RequestContext`` will contain a variable ``STATIC_URL``, providing the
value of the :setting:`STATIC_URL` setting.
View
14 docs/ref/templates/builtins.txt
@@ -156,8 +156,6 @@ In this syntax, each value gets interpreted as a literal string, and there's no
way to specify variable values. Or literal commas. Or spaces. Did we mention
you shouldn't use this syntax in any new projects?
-.. versionadded:: 1.3
-
By default, when you use the ``as`` keyword with the cycle tag, the
usage of ``{% cycle %}`` that declares the cycle will itself output
the first value in the cycle. This could be a problem if you want to
@@ -676,9 +674,6 @@ including it. This example produces the output ``"Hello, John"``:
{{ greeting }}, {{ person|default:"friend" }}!
-.. versionchanged:: 1.3
- Additional context and exclusive context.
-
You can pass additional context to the template using keyword arguments::
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}
@@ -710,8 +705,6 @@ registered in ``somelibrary`` and ``otherlibrary`` located in package
{% load somelibrary package.otherlibrary %}
-.. versionchanged:: 1.3
-
You can also selectively load individual filters or tags from a library, using
the ``from`` argument. In this example, the template tags/filters named ``foo``
and ``bar`` will be loaded from ``somelibrary``::
@@ -1076,9 +1069,6 @@ which is rounded up to 88).
with
^^^^
-.. versionchanged:: 1.3
- New keyword argument format and multiple variable assignments.
-
Caches a complex variable under a simpler name. This is useful when accessing
an "expensive" method (e.g., one that hits the database) multiple times.
@@ -1261,7 +1251,7 @@ S English ordinal suffix for day of the ``'st'``, ``'nd'``,
month, 2 characters.
t Number of days in the given month. ``28`` to ``31``
T Time zone of this machine. ``'EST'``, ``'MDT'``
-u Microseconds. ``0`` to ``999999``
+u Microseconds. ``000000`` to ``999999``
U Seconds since the Unix Epoch
(January 1 1970 00:00:00 UTC).
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
@@ -2126,8 +2116,6 @@ For example::
If ``value`` is ``"http://www.example.org/foo?a=b&c=d"``, the output will be
``"http%3A//www.example.org/foo%3Fa%3Db%26c%3Dd"``.
-.. versionadded:: 1.3
-
An optional argument containing the characters which should not be escaped can
be provided.
View
22 docs/releases/1.5.txt
@@ -133,6 +133,8 @@ Django 1.5 also includes several smaller improvements worth noting:
* The :ref:`receiver <connecting-receiver-functions>` decorator is now able to
connect to more than one signal by supplying a list of signals.
+* In the admin, you can now filter users by groups which they are members of.
+
* :meth:`QuerySet.bulk_create()
<django.db.models.query.QuerySet.bulk_create>` now has a batch_size
argument. By default the batch_size is unlimited except for SQLite where
@@ -167,6 +169,21 @@ 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 year and month archive class-based views
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:class:`~django.views.generic.dates.YearArchiveView` and
+:class:`~django.views.generic.dates.MonthArchiveView` were documented to
+provide a ``date_list`` sorted in ascending order in the context, like their
+function-based predecessors, but it actually was in descending order. In 1.5,
+the documented order was restored. You may want to add (or remove) the
+``reversed`` keyword when you're iterating on ``date_list`` in a template::
+
+ {% for date in date_list reversed %}
+
+:class:`~django.views.generic.dates.ArchiveIndexView` still provides a
+``date_list`` in descending order.
+
Context in TemplateView
~~~~~~~~~~~~~~~~~~~~~~~
@@ -362,6 +379,11 @@ Miscellaneous
function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is
available at :func:`django.utils.html.remove_tags`.
+* Uploaded files are no longer created as executable by default. If you need
+ them to be executeable change :setting:`FILE_UPLOAD_PERMISSIONS` to your
+ needs. The new default value is `0666` (octal) and the current umask value
+ is first masked out.
+
Features deprecated in 1.5
==========================
View
13 docs/topics/auth.txt
@@ -872,8 +872,6 @@ How to log a user out
Login and logout signals
------------------------
-.. versionadded:: 1.3
-
The auth framework uses two :doc:`signals </topics/signals>` that can be used
for notification when a user logs in or out.
@@ -972,8 +970,6 @@ The login_required decorator
context variable which stores the redirect path will use the value of
``redirect_field_name`` as its key rather than ``"next"`` (the default).
- .. versionadded:: 1.3
-
:func:`~django.contrib.auth.decorators.login_required` also takes an
optional ``login_url`` parameter. Example::
@@ -1201,9 +1197,6 @@ includes a few other useful built-in views located in
that can be used to reset the password, and sending that link to the
user's registered email address.
- .. versionchanged:: 1.3