mirror of https://github.com/django/django.git
Merged recent Django trunk changes.
This commit is contained in:
commit
0229209c84
1
AUTHORS
1
AUTHORS
|
@ -33,6 +33,7 @@ The PRIMARY AUTHORS are (and/or have been):
|
||||||
* Florian Apolloner
|
* Florian Apolloner
|
||||||
* Jeremy Dunck
|
* Jeremy Dunck
|
||||||
* Bryan Veloso
|
* Bryan Veloso
|
||||||
|
* Preston Holmes
|
||||||
|
|
||||||
More information on the main contributors to Django can be found in
|
More information on the main contributors to Django can be found in
|
||||||
docs/internals/committers.txt.
|
docs/internals/committers.txt.
|
||||||
|
|
|
@ -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/
|
|
@ -54,7 +54,7 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
add_form = UserCreationForm
|
add_form = UserCreationForm
|
||||||
change_password_form = AdminPasswordChangeForm
|
change_password_form = AdminPasswordChangeForm
|
||||||
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
|
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')
|
search_fields = ('username', 'first_name', 'last_name', 'email')
|
||||||
ordering = ('username',)
|
ordering = ('username',)
|
||||||
filter_horizontal = ('user_permissions',)
|
filter_horizontal = ('user_permissions',)
|
||||||
|
|
|
@ -28,7 +28,7 @@ def update_last_login(sender, user, **kwargs):
|
||||||
the user logging in.
|
the user logging in.
|
||||||
"""
|
"""
|
||||||
user.last_login = timezone.now()
|
user.last_login = timezone.now()
|
||||||
user.save()
|
user.save(update_fields=['last_login'])
|
||||||
user_logged_in.connect(update_last_login)
|
user_logged_in.connect(update_last_login)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from django.contrib.auth import signals
|
from django.contrib.auth import signals
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.tests.utils import skipIfCustomUser
|
from django.contrib.auth.tests.utils import skipIfCustomUser
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.test.client import RequestFactory
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,3 +51,16 @@ class SignalTestCase(TestCase):
|
||||||
self.client.get('/logout/next_page/')
|
self.client.get('/logout/next_page/')
|
||||||
self.assertEqual(len(self.logged_out), 1)
|
self.assertEqual(len(self.logged_out), 1)
|
||||||
self.assertEqual(self.logged_out[0].username, 'testclient')
|
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)
|
||||||
|
|
|
@ -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 %}
|
{% autoescape off %}{% for item in map_options.items %} '{{ item.0 }}' : {{ item.1 }}{% if not forloop.last %},{% endif %}
|
||||||
{% endfor %}{% endautoescape %} };{% endblock %}
|
{% endfor %}{% endautoescape %} };{% endblock %}
|
||||||
// The admin map for this geometry field.
|
// The admin map for this geometry field.
|
||||||
|
{% block map_creation %}
|
||||||
{{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
|
{{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
|
||||||
// Base Layer
|
// Base Layer
|
||||||
{{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS("{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'{{ wms_options|safe }}});{% endblock %}
|
{{ 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);
|
{{ module }}.map.addLayer({{ module }}.layers.base);
|
||||||
|
{% endblock %}
|
||||||
{% block extra_layers %}{% endblock %}
|
{% block extra_layers %}{% endblock %}
|
||||||
{% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
|
{% 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 }}");
|
{{ module }}.layers.vector = new OpenLayers.Layer.Vector(" {{ field_name }}");
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.utils.unittest import TestCase
|
|
||||||
from django.contrib.gis.db.models import Union, Extent3D
|
from django.contrib.gis.db.models import Union, Extent3D
|
||||||
from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
|
from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
|
||||||
from django.contrib.gis.utils import LayerMapping, LayerMapError
|
from django.contrib.gis.utils import LayerMapping, LayerMapError
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
from .models import (City3D, Interstate2D, Interstate3D, InterstateProj2D,
|
from .models import (City3D, Interstate2D, Interstate3D, InterstateProj2D,
|
||||||
InterstateProj3D, Point2D, Point3D, MultiPoint3D, Polygon2D, Polygon3D)
|
InterstateProj3D, Point2D, Point3D, MultiPoint3D, Polygon2D, Polygon3D)
|
||||||
|
|
||||||
|
|
||||||
data_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'data'))
|
data_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'data'))
|
||||||
city_file = os.path.join(data_path, 'cities', 'cities.shp')
|
city_file = os.path.join(data_path, 'cities', 'cities.shp')
|
||||||
vrt_file = os.path.join(data_path, 'test_vrt', 'test_vrt.vrt')
|
vrt_file = os.path.join(data_path, 'test_vrt', 'test_vrt.vrt')
|
||||||
|
@ -46,12 +47,11 @@ interstate_data = (
|
||||||
# Bounding box polygon for inner-loop of Houston (in projected coordinate
|
# Bounding box polygon for inner-loop of Houston (in projected coordinate
|
||||||
# system 32140), with elevation values from the National Elevation Dataset
|
# system 32140), with elevation values from the National Elevation Dataset
|
||||||
# (see above).
|
# (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_data = (
|
||||||
bbox_z = (21.71, 13.21, 9.12, 16.40, 21.71)
|
'POLYGON((941527.97 4225693.20,962596.48 4226349.75,963152.57 4209023.95,942051.75 4208366.38,941527.97 4225693.20))',
|
||||||
def gen_bbox():
|
(21.71, 13.21, 9.12, 16.40, 21.71)
|
||||||
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
|
|
||||||
|
|
||||||
class Geo3DTest(TestCase):
|
class Geo3DTest(TestCase):
|
||||||
"""
|
"""
|
||||||
|
@ -63,20 +63,7 @@ class Geo3DTest(TestCase):
|
||||||
http://postgis.refractions.net/documentation/manual-1.4/ch08.html#PostGIS_3D_Functions
|
http://postgis.refractions.net/documentation/manual-1.4/ch08.html#PostGIS_3D_Functions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def test01_3d(self):
|
def _load_interstate_data(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)
|
|
||||||
|
|
||||||
# Interstate (2D / 3D and Geographic/Projected variants)
|
# Interstate (2D / 3D and Geographic/Projected variants)
|
||||||
for name, line, exp_z in interstate_data:
|
for name, line, exp_z in interstate_data:
|
||||||
line_3d = GEOSGeometry(line, srid=4269)
|
line_3d = GEOSGeometry(line, srid=4269)
|
||||||
|
@ -90,26 +77,51 @@ class Geo3DTest(TestCase):
|
||||||
Interstate2D.objects.create(name=name, line=line_2d)
|
Interstate2D.objects.create(name=name, line=line_2d)
|
||||||
InterstateProj2D.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
|
def _load_city_data(self):
|
||||||
# Z values -- shouldn't change because of coordinate system.
|
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 = Interstate3D.objects.get(name=name)
|
||||||
interstate_proj = InterstateProj3D.objects.get(name=name)
|
interstate_proj = InterstateProj3D.objects.get(name=name)
|
||||||
for i in [interstate, interstate_proj]:
|
for i in [interstate, interstate_proj]:
|
||||||
self.assertTrue(i.line.hasz)
|
self.assertTrue(i.line.hasz)
|
||||||
self.assertEqual(exp_z, tuple(i.line.z))
|
self.assertEqual(exp_z, tuple(i.line.z))
|
||||||
|
|
||||||
# Creating 3D Polygon.
|
self._load_city_data()
|
||||||
bbox2d, bbox3d = gen_bbox()
|
for name, pnt_data in city_data:
|
||||||
Polygon2D.objects.create(name='2D BBox', poly=bbox2d)
|
city = City3D.objects.get(name=name)
|
||||||
Polygon3D.objects.create(name='3D BBox', poly=bbox3d)
|
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')
|
p3d = Polygon3D.objects.get(name='3D BBox')
|
||||||
self.assertTrue(p3d.poly.hasz)
|
self.assertTrue(p3d.poly.hasz)
|
||||||
self.assertEqual(bbox3d, p3d.poly)
|
self.assertIsInstance(p3d.poly, Polygon)
|
||||||
|
self.assertEqual(p3d.poly.srid, 32140)
|
||||||
def test01a_3d_layermapping(self):
|
|
||||||
"Testing LayerMapping on 3D models."
|
|
||||||
from .models import Point2D, Point3D
|
|
||||||
|
|
||||||
|
def test_3d_layermapping(self):
|
||||||
|
"""
|
||||||
|
Testing LayerMapping on 3D models.
|
||||||
|
"""
|
||||||
point_mapping = {'point' : 'POINT'}
|
point_mapping = {'point' : 'POINT'}
|
||||||
mpoint_mapping = {'mpoint' : 'MULTIPOINT'}
|
mpoint_mapping = {'mpoint' : 'MULTIPOINT'}
|
||||||
|
|
||||||
|
@ -134,34 +146,46 @@ class Geo3DTest(TestCase):
|
||||||
lm.save()
|
lm.save()
|
||||||
self.assertEqual(3, MultiPoint3D.objects.count())
|
self.assertEqual(3, MultiPoint3D.objects.count())
|
||||||
|
|
||||||
def test02a_kml(self):
|
def test_kml(self):
|
||||||
"Test GeoQuerySet.kml() with Z values."
|
"""
|
||||||
|
Test GeoQuerySet.kml() with Z values.
|
||||||
|
"""
|
||||||
|
self._load_city_data()
|
||||||
h = City3D.objects.kml(precision=6).get(name='Houston')
|
h = City3D.objects.kml(precision=6).get(name='Houston')
|
||||||
# KML should be 3D.
|
# KML should be 3D.
|
||||||
# `SELECT ST_AsKML(point, 6) FROM geo3d_city3d WHERE name = 'Houston';`
|
# `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>$')
|
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))
|
self.assertTrue(ref_kml_regex.match(h.kml))
|
||||||
|
|
||||||
def test02b_geojson(self):
|
def test_geojson(self):
|
||||||
"Test GeoQuerySet.geojson() with Z values."
|
"""
|
||||||
|
Test GeoQuerySet.geojson() with Z values.
|
||||||
|
"""
|
||||||
|
self._load_city_data()
|
||||||
h = City3D.objects.geojson(precision=6).get(name='Houston')
|
h = City3D.objects.geojson(precision=6).get(name='Houston')
|
||||||
# GeoJSON should be 3D
|
# GeoJSON should be 3D
|
||||||
# `SELECT ST_AsGeoJSON(point, 6) FROM geo3d_city3d WHERE name='Houston';`
|
# `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+)?\]}$')
|
ref_json_regex = re.compile(r'^{"type":"Point","coordinates":\[-95.363151,29.763374,18(\.0+)?\]}$')
|
||||||
self.assertTrue(ref_json_regex.match(h.geojson))
|
self.assertTrue(ref_json_regex.match(h.geojson))
|
||||||
|
|
||||||
def test03a_union(self):
|
def test_union(self):
|
||||||
"Testing the Union aggregate of 3D models."
|
"""
|
||||||
|
Testing the Union aggregate of 3D models.
|
||||||
|
"""
|
||||||
# PostGIS query that returned the reference EWKT for this test:
|
# PostGIS query that returned the reference EWKT for this test:
|
||||||
# `SELECT ST_AsText(ST_Union(point)) FROM geo3d_city3d;`
|
# `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_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)
|
ref_union = GEOSGeometry(ref_ewkt)
|
||||||
union = City3D.objects.aggregate(Union('point'))['point__union']
|
union = City3D.objects.aggregate(Union('point'))['point__union']
|
||||||
self.assertTrue(union.hasz)
|
self.assertTrue(union.hasz)
|
||||||
self.assertEqual(ref_union, union)
|
self.assertEqual(ref_union, union)
|
||||||
|
|
||||||
def test03b_extent(self):
|
def test_extent(self):
|
||||||
"Testing the Extent3D aggregate for 3D models."
|
"""
|
||||||
|
Testing the Extent3D aggregate for 3D models.
|
||||||
|
"""
|
||||||
|
self._load_city_data()
|
||||||
# `SELECT ST_Extent3D(point) FROM geo3d_city3d;`
|
# `SELECT ST_Extent3D(point) FROM geo3d_city3d;`
|
||||||
ref_extent3d = (-123.305196, -41.315268, 14,174.783117, 48.462611, 1433)
|
ref_extent3d = (-123.305196, -41.315268, 14,174.783117, 48.462611, 1433)
|
||||||
extent1 = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
|
extent1 = City3D.objects.aggregate(Extent3D('point'))['point__extent3d']
|
||||||
|
@ -174,8 +198,11 @@ class Geo3DTest(TestCase):
|
||||||
for e3d in [extent1, extent2]:
|
for e3d in [extent1, extent2]:
|
||||||
check_extent3d(e3d)
|
check_extent3d(e3d)
|
||||||
|
|
||||||
def test04_perimeter(self):
|
def test_perimeter(self):
|
||||||
"Testing GeoQuerySet.perimeter() on 3D fields."
|
"""
|
||||||
|
Testing GeoQuerySet.perimeter() on 3D fields.
|
||||||
|
"""
|
||||||
|
self._load_polygon_data()
|
||||||
# Reference query for values below:
|
# Reference query for values below:
|
||||||
# `SELECT ST_Perimeter3D(poly), ST_Perimeter2D(poly) FROM geo3d_polygon3d;`
|
# `SELECT ST_Perimeter3D(poly), ST_Perimeter2D(poly) FROM geo3d_polygon3d;`
|
||||||
ref_perim_3d = 76859.2620451
|
ref_perim_3d = 76859.2620451
|
||||||
|
@ -188,12 +215,15 @@ class Geo3DTest(TestCase):
|
||||||
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
|
Polygon3D.objects.perimeter().get(name='3D BBox').perimeter.m,
|
||||||
tol)
|
tol)
|
||||||
|
|
||||||
def test05_length(self):
|
def test_length(self):
|
||||||
"Testing GeoQuerySet.length() on 3D fields."
|
"""
|
||||||
|
Testing GeoQuerySet.length() on 3D fields.
|
||||||
|
"""
|
||||||
# ST_Length_Spheroid Z-aware, and thus does not need to use
|
# ST_Length_Spheroid Z-aware, and thus does not need to use
|
||||||
# a separate function internally.
|
# a separate function internally.
|
||||||
# `SELECT ST_Length_Spheroid(line, 'SPHEROID["GRS 1980",6378137,298.257222101]')
|
# `SELECT ST_Length_Spheroid(line, 'SPHEROID["GRS 1980",6378137,298.257222101]')
|
||||||
# FROM geo3d_interstate[2d|3d];`
|
# FROM geo3d_interstate[2d|3d];`
|
||||||
|
self._load_interstate_data()
|
||||||
tol = 3
|
tol = 3
|
||||||
ref_length_2d = 4368.1721949481
|
ref_length_2d = 4368.1721949481
|
||||||
ref_length_3d = 4368.62547052088
|
ref_length_3d = 4368.62547052088
|
||||||
|
@ -217,16 +247,22 @@ class Geo3DTest(TestCase):
|
||||||
InterstateProj3D.objects.length().get(name='I-45').length.m,
|
InterstateProj3D.objects.length().get(name='I-45').length.m,
|
||||||
tol)
|
tol)
|
||||||
|
|
||||||
def test06_scale(self):
|
def test_scale(self):
|
||||||
"Testing GeoQuerySet.scale() on Z values."
|
"""
|
||||||
|
Testing GeoQuerySet.scale() on Z values.
|
||||||
|
"""
|
||||||
|
self._load_city_data()
|
||||||
# Mapping of City name to reference Z values.
|
# Mapping of City name to reference Z values.
|
||||||
zscales = (-3, 4, 23)
|
zscales = (-3, 4, 23)
|
||||||
for zscale in zscales:
|
for zscale in zscales:
|
||||||
for city in City3D.objects.scale(1.0, 1.0, zscale):
|
for city in City3D.objects.scale(1.0, 1.0, zscale):
|
||||||
self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z)
|
self.assertEqual(city_dict[city.name][2] * zscale, city.scale.z)
|
||||||
|
|
||||||
def test07_translate(self):
|
def test_translate(self):
|
||||||
"Testing GeoQuerySet.translate() on Z values."
|
"""
|
||||||
|
Testing GeoQuerySet.translate() on Z values.
|
||||||
|
"""
|
||||||
|
self._load_city_data()
|
||||||
ztranslations = (5.23, 23, -17)
|
ztranslations = (5.23, 23, -17)
|
||||||
for ztrans in ztranslations:
|
for ztrans in ztranslations:
|
||||||
for city in City3D.objects.translate(0, 0, ztrans):
|
for city in City3D.objects.translate(0, 0, ztrans):
|
||||||
|
|
|
@ -520,8 +520,8 @@ class GeoQuerySetTest(TestCase):
|
||||||
if oracle:
|
if oracle:
|
||||||
# No precision parameter for 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>')
|
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:
|
elif spatialite and connection.ops.spatial_version < (3, 0, 0):
|
||||||
# Spatialite has extra colon in SrsName
|
# 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>')
|
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:
|
else:
|
||||||
gml_regex = re.compile(r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>-104\.60925\d+,38\.255001</gml:coordinates></gml:Point>')
|
gml_regex = re.compile(r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>-104\.60925\d+,38\.255001</gml:coordinates></gml:Point>')
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.contrib.gis.gdal import DataSource
|
||||||
from django.contrib.gis.tests.utils import mysql
|
from django.contrib.gis.tests.utils import mysql
|
||||||
from django.contrib.gis.utils.layermapping import (LayerMapping, LayerMapError,
|
from django.contrib.gis.utils.layermapping import (LayerMapping, LayerMapError,
|
||||||
InvalidDecimal, MissingForeignKey)
|
InvalidDecimal, MissingForeignKey)
|
||||||
|
from django.db import router
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
|
@ -26,6 +27,7 @@ NAMES = ['Bexar', 'Galveston', 'Harris', 'Honolulu', 'Pueblo']
|
||||||
NUMS = [1, 2, 1, 19, 1] # Number of polygons for each.
|
NUMS = [1, 2, 1, 19, 1] # Number of polygons for each.
|
||||||
STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
|
STATES = ['Texas', 'Texas', 'Texas', 'Hawaii', 'Colorado']
|
||||||
|
|
||||||
|
|
||||||
class LayerMapTest(TestCase):
|
class LayerMapTest(TestCase):
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
|
@ -281,3 +283,31 @@ class LayerMapTest(TestCase):
|
||||||
lm.save(silent=True, strict=True)
|
lm.save(silent=True, strict=True)
|
||||||
self.assertEqual(City.objects.count(), 3)
|
self.assertEqual(City.objects.count(), 3)
|
||||||
self.assertEqual(City.objects.all().order_by('name_txt')[0].name_txt, "Houston")
|
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')
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import sys
|
import sys
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
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.db.models import GeometryField
|
||||||
from django.contrib.gis.gdal import (CoordTransform, DataSource,
|
from django.contrib.gis.gdal import (CoordTransform, DataSource,
|
||||||
OGRException, OGRGeometry, OGRGeomType, SpatialReference)
|
OGRException, OGRGeometry, OGRGeomType, SpatialReference)
|
||||||
|
@ -67,7 +67,7 @@ class LayerMapping(object):
|
||||||
def __init__(self, model, data, mapping, layer=0,
|
def __init__(self, model, data, mapping, layer=0,
|
||||||
source_srs=None, encoding=None,
|
source_srs=None, encoding=None,
|
||||||
transaction_mode='commit_on_success',
|
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 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
|
a DataSource (or string path to an OGR-supported data file), and a mapping
|
||||||
|
@ -81,8 +81,8 @@ class LayerMapping(object):
|
||||||
self.ds = data
|
self.ds = data
|
||||||
self.layer = self.ds[layer]
|
self.layer = self.ds[layer]
|
||||||
|
|
||||||
self.using = using
|
self.using = using if using is not None else router.db_for_write(model)
|
||||||
self.spatial_backend = connections[using].ops
|
self.spatial_backend = connections[self.using].ops
|
||||||
|
|
||||||
# Setting the mapping & model attributes.
|
# Setting the mapping & model attributes.
|
||||||
self.mapping = mapping
|
self.mapping = mapping
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.contrib.sessions.backends.file import SessionStore as FileSession
|
||||||
from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession
|
from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession
|
||||||
from django.contrib.sessions.models import Session
|
from django.contrib.sessions.models import Session
|
||||||
from django.contrib.sessions.middleware import SessionMiddleware
|
from django.contrib.sessions.middleware import SessionMiddleware
|
||||||
|
from django.core.cache import DEFAULT_CACHE_ALIAS
|
||||||
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
|
@ -133,6 +134,9 @@ class SessionTestsMixin(object):
|
||||||
self.assertTrue(self.session.modified)
|
self.assertTrue(self.session.modified)
|
||||||
|
|
||||||
def test_save(self):
|
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.session.save()
|
||||||
self.assertTrue(self.session.exists(self.session.session_key))
|
self.assertTrue(self.session.exists(self.session.session_key))
|
||||||
|
|
||||||
|
@ -296,6 +300,8 @@ class CacheDBSessionTests(SessionTestsMixin, TestCase):
|
||||||
|
|
||||||
backend = CacheDBSession
|
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):
|
def test_exists_searches_cache_first(self):
|
||||||
self.session.save()
|
self.session.save()
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
|
|
|
@ -192,7 +192,10 @@ class FileSystemStorage(Storage):
|
||||||
else:
|
else:
|
||||||
# This fun binary flag incantation makes os.open throw an
|
# This fun binary flag incantation makes os.open throw an
|
||||||
# OSError if the file already exists before we open it.
|
# 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:
|
try:
|
||||||
locks.lock(fd, locks.LOCK_EX)
|
locks.lock(fd, locks.LOCK_EX)
|
||||||
_file = None
|
_file = None
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
@ -7,10 +8,9 @@ from django import http
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.log import getLogger
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
|
|
||||||
class BaseHandler(object):
|
class BaseHandler(object):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
@ -10,9 +11,8 @@ from django.core.handlers import base
|
||||||
from django.core.urlresolvers import set_script_prefix
|
from django.core.urlresolvers import set_script_prefix
|
||||||
from django.utils import datastructures
|
from django.utils import datastructures
|
||||||
from django.utils.encoding import force_str, force_text, iri_to_uri
|
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
|
# See http://www.iana.org/assignments/http-status-codes
|
||||||
|
|
|
@ -20,5 +20,7 @@ class EmailBackend(BaseEmailBackend):
|
||||||
|
|
||||||
def send_messages(self, messages):
|
def send_messages(self, messages):
|
||||||
"""Redirect messages to the dummy outbox"""
|
"""Redirect messages to the dummy outbox"""
|
||||||
|
for message in messages: # .message() triggers header validation
|
||||||
|
message.message()
|
||||||
mail.outbox.extend(messages)
|
mail.outbox.extend(messages)
|
||||||
return len(messages)
|
return len(messages)
|
||||||
|
|
|
@ -3,6 +3,7 @@ PostgreSQL database backend for Django.
|
||||||
|
|
||||||
Requires psycopg 2: http://initd.org/projects/psycopg2
|
Requires psycopg 2: http://initd.org/projects/psycopg2
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django.db import utils
|
from django.db import utils
|
||||||
|
@ -14,7 +15,6 @@ from django.db.backends.postgresql_psycopg2.creation import DatabaseCreation
|
||||||
from django.db.backends.postgresql_psycopg2.version import get_version
|
from django.db.backends.postgresql_psycopg2.version import get_version
|
||||||
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.log import getLogger
|
|
||||||
from django.utils.safestring import SafeText, SafeBytes
|
from django.utils.safestring import SafeText, SafeBytes
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
|
@ -33,7 +33,7 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
|
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
|
||||||
psycopg2.extensions.register_adapter(SafeText, 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):
|
def utc_tzinfo_factory(offset):
|
||||||
if offset != 0:
|
if offset != 0:
|
||||||
|
|
|
@ -3,15 +3,15 @@ from __future__ import unicode_literals
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.log import getLogger
|
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
|
||||||
logger = getLogger('django.db.backends')
|
logger = logging.getLogger('django.db.backends')
|
||||||
|
|
||||||
|
|
||||||
class CursorWrapper(object):
|
class CursorWrapper(object):
|
||||||
|
|
|
@ -609,8 +609,12 @@ class SQLCompiler(object):
|
||||||
restricted = False
|
restricted = False
|
||||||
|
|
||||||
for f, model in opts.get_fields_with_model():
|
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,
|
if not select_related_descend(f, restricted, requested,
|
||||||
only_load.get(model or self.query.model)):
|
only_load.get(field_model)):
|
||||||
continue
|
continue
|
||||||
# The "avoid" set is aliases we want to avoid just for this
|
# The "avoid" set is aliases we want to avoid just for this
|
||||||
# particular branch of the recursion. They aren't permanently
|
# particular branch of the recursion. They aren't permanently
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -6,9 +7,9 @@ from django import http
|
||||||
from django.core.mail import mail_managers
|
from django.core.mail import mail_managers
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
from django.core import urlresolvers
|
from django.core import urlresolvers
|
||||||
from django.utils.log import getLogger
|
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
|
||||||
|
logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
|
|
||||||
class CommonMiddleware(object):
|
class CommonMiddleware(object):
|
||||||
|
|
|
@ -7,6 +7,7 @@ against request forgeries from other sites.
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
@ -15,10 +16,10 @@ from django.core.urlresolvers import get_callable
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import same_origin
|
from django.utils.http import same_origin
|
||||||
from django.utils.log import getLogger
|
|
||||||
from django.utils.crypto import constant_time_compare, get_random_string
|
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_NO_REFERER = "Referer checking failed - no Referer."
|
||||||
REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
|
REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
|
||||||
|
|
|
@ -649,6 +649,7 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
self.assertEqual(response.status_code, status_code,
|
self.assertEqual(response.status_code, status_code,
|
||||||
msg_prefix + "Couldn't retrieve content: Response code was %d"
|
msg_prefix + "Couldn't retrieve content: Response code was %d"
|
||||||
" (expected %d)" % (response.status_code, status_code))
|
" (expected %d)" % (response.status_code, status_code))
|
||||||
|
text = force_text(text, encoding=response._charset)
|
||||||
content = response.content.decode(response._charset)
|
content = response.content.decode(response._charset)
|
||||||
if html:
|
if html:
|
||||||
content = assert_and_parse_html(self, content, None,
|
content = assert_and_parse_html(self, content, None,
|
||||||
|
@ -684,6 +685,7 @@ class TransactionTestCase(SimpleTestCase):
|
||||||
self.assertEqual(response.status_code, status_code,
|
self.assertEqual(response.status_code, status_code,
|
||||||
msg_prefix + "Couldn't retrieve content: Response code was %d"
|
msg_prefix + "Couldn't retrieve content: Response code was %d"
|
||||||
" (expected %d)" % (response.status_code, status_code))
|
" (expected %d)" % (response.status_code, status_code))
|
||||||
|
text = force_text(text, encoding=response._charset)
|
||||||
content = response.content.decode(response._charset)
|
content = response.content.decode(response._charset)
|
||||||
if html:
|
if html:
|
||||||
content = assert_and_parse_html(self, content, None,
|
content = assert_and_parse_html(self, content, None,
|
||||||
|
|
|
@ -110,8 +110,8 @@ class TimeFormat(Formatter):
|
||||||
return '%02d' % self.data.second
|
return '%02d' % self.data.second
|
||||||
|
|
||||||
def u(self):
|
def u(self):
|
||||||
"Microseconds"
|
"Microseconds; i.e. '000000' to '999999'"
|
||||||
return self.data.microsecond
|
return '%06d' %self.data.microsecond
|
||||||
|
|
||||||
|
|
||||||
class DateFormat(TimeFormat):
|
class DateFormat(TimeFormat):
|
||||||
|
|
|
@ -42,29 +42,26 @@ def escape(text):
|
||||||
return mark_safe(force_text(text).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", '''))
|
return mark_safe(force_text(text).replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"').replace("'", '''))
|
||||||
escape = allow_lazy(escape, six.text_type)
|
escape = allow_lazy(escape, six.text_type)
|
||||||
|
|
||||||
_base_js_escapes = (
|
_js_escapes = {
|
||||||
('\\', '\\u005C'),
|
ord('\\'): '\\u005C',
|
||||||
('\'', '\\u0027'),
|
ord('\''): '\\u0027',
|
||||||
('"', '\\u0022'),
|
ord('"'): '\\u0022',
|
||||||
('>', '\\u003E'),
|
ord('>'): '\\u003E',
|
||||||
('<', '\\u003C'),
|
ord('<'): '\\u003C',
|
||||||
('&', '\\u0026'),
|
ord('&'): '\\u0026',
|
||||||
('=', '\\u003D'),
|
ord('='): '\\u003D',
|
||||||
('-', '\\u002D'),
|
ord('-'): '\\u002D',
|
||||||
(';', '\\u003B'),
|
ord(';'): '\\u003B',
|
||||||
('\u2028', '\\u2028'),
|
ord('\u2028'): '\\u2028',
|
||||||
('\u2029', '\\u2029')
|
ord('\u2029'): '\\u2029'
|
||||||
)
|
}
|
||||||
|
|
||||||
# Escape every ASCII character with a value less than 32.
|
# Escape every ASCII character with a value less than 32.
|
||||||
_js_escapes = (_base_js_escapes +
|
_js_escapes.update((ord('%c' % z), '\\u%04X' % z) for z in range(32))
|
||||||
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
|
|
||||||
|
|
||||||
def escapejs(value):
|
def escapejs(value):
|
||||||
"""Hex encodes characters for use in JavaScript strings."""
|
"""Hex encodes characters for use in JavaScript strings."""
|
||||||
for bad, good in _js_escapes:
|
return mark_safe(force_text(value).translate(_js_escapes))
|
||||||
value = mark_safe(force_text(value).replace(bad, good))
|
|
||||||
return value
|
|
||||||
escapejs = allow_lazy(escapejs, six.text_type)
|
escapejs = allow_lazy(escapejs, six.text_type)
|
||||||
|
|
||||||
def conditional_escape(text):
|
def conditional_escape(text):
|
||||||
|
|
|
@ -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:
|
if isinstance(number, int) and not use_grouping and not decimal_pos:
|
||||||
return mark_safe(six.text_type(number))
|
return mark_safe(six.text_type(number))
|
||||||
# sign
|
# sign
|
||||||
if float(number) < 0:
|
sign = ''
|
||||||
sign = '-'
|
|
||||||
else:
|
|
||||||
sign = ''
|
|
||||||
str_number = six.text_type(number)
|
str_number = six.text_type(number)
|
||||||
if str_number[0] == '-':
|
if str_number[0] == '-':
|
||||||
|
sign = '-'
|
||||||
str_number = str_number[1:]
|
str_number = str_number[1:]
|
||||||
# decimal part
|
# decimal part
|
||||||
if '.' in str_number:
|
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_gd += digit
|
||||||
int_part = int_part_gd[::-1]
|
int_part = int_part_gd[::-1]
|
||||||
return sign + int_part + dec_part
|
return sign + int_part + dec_part
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
Decorators for views based on HTTP headers.
|
Decorators for views based on HTTP headers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from django.utils.decorators import decorator_from_middleware, available_attrs
|
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.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.middleware.http import ConditionalGetMiddleware
|
||||||
from django.http import HttpResponseNotAllowed, HttpResponseNotModified, HttpResponse
|
from django.http import HttpResponseNotAllowed, HttpResponseNotModified, HttpResponse
|
||||||
|
|
||||||
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
|
|
||||||
def require_http_methods(request_method_list):
|
def require_http_methods(request_method_list):
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import logging
|
||||||
from functools import update_wrapper
|
from functools import update_wrapper
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.log import getLogger
|
|
||||||
from django.utils.decorators import classonlymethod
|
from django.utils.decorators import classonlymethod
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
|
|
||||||
class ContextMixin(object):
|
class ContextMixin(object):
|
||||||
|
|
|
@ -377,7 +377,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
"""
|
"""
|
||||||
return self.date_list_period
|
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
|
Get a date list by calling `queryset.dates()`, checking along the way
|
||||||
for empty lists that aren't allowed.
|
for empty lists that aren't allowed.
|
||||||
|
@ -387,7 +387,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View):
|
||||||
if date_type is None:
|
if date_type is None:
|
||||||
date_type = self.get_date_list_period()
|
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:
|
if date_list is not None and not date_list and not allow_empty:
|
||||||
name = force_text(queryset.model._meta.verbose_name_plural)
|
name = force_text(queryset.model._meta.verbose_name_plural)
|
||||||
raise Http404(_("No %(verbose_name_plural)s available") %
|
raise Http404(_("No %(verbose_name_plural)s available") %
|
||||||
|
@ -409,7 +409,7 @@ class BaseArchiveIndexView(BaseDateListView):
|
||||||
Return (date_list, items, extra_context) for this request.
|
Return (date_list, items, extra_context) for this request.
|
||||||
"""
|
"""
|
||||||
qs = self.get_dated_queryset(ordering='-%s' % self.get_date_field())
|
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:
|
if not date_list:
|
||||||
qs = qs.none()
|
qs = qs.none()
|
||||||
|
|
|
@ -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
|
* If the argument was a template variable, our function is passed the
|
||||||
current value of the variable, not the variable itself.
|
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
|
If your template tag needs to access the current context, you can use the
|
||||||
``takes_context`` argument when registering your tag:
|
``takes_context`` argument when registering your tag:
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,6 @@ setting.
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Server error emails are sent using the logging framework, so you can
|
Server error emails are sent using the logging framework, so you can
|
||||||
customize this behavior by :doc:`customizing your logging configuration
|
customize this behavior by :doc:`customizing your logging configuration
|
||||||
</topics/logging>`.
|
</topics/logging>`.
|
||||||
|
@ -99,8 +97,6 @@ The best way to disable this behavior is to set
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
404 errors are logged using the logging framework. By default, these log
|
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
|
records are ignored, but you can use them for error reporting by writing a
|
||||||
handler and :doc:`configuring logging </topics/logging>` appropriately.
|
handler and :doc:`configuring logging </topics/logging>` appropriately.
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
Managing static files
|
Managing static files
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Django developers mostly concern themselves with the dynamic parts of web
|
Django developers mostly concern themselves with the dynamic parts of web
|
||||||
applications -- the views and templates that render anew for each request. But
|
applications -- the views and templates that render anew for each request. But
|
||||||
web applications have other parts: the static files (images, CSS,
|
web applications have other parts: the static files (images, CSS,
|
||||||
|
|
|
@ -407,6 +407,18 @@ Jeremy Dunck
|
||||||
.. _vlogger: http://youtube.com/bryanveloso/
|
.. _vlogger: http://youtube.com/bryanveloso/
|
||||||
.. _shoutcaster: http://twitch.tv/vlogalonstar/
|
.. _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
|
Specialists
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ these changes.
|
||||||
|
|
||||||
* The function-based generic view modules will be removed in favor of their
|
* The function-based generic view modules will be removed in favor of their
|
||||||
class-based equivalents, outlined :doc:`here
|
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
|
* The :class:`~django.core.servers.basehttp.AdminMediaHandler` will be
|
||||||
removed. In its place use
|
removed. In its place use
|
||||||
|
|
|
@ -155,8 +155,6 @@ Certain APIs are explicitly marked as "internal" in a couple of ways:
|
||||||
Local flavors
|
Local flavors
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
:mod:`django.contrib.localflavor` contains assorted pieces of code
|
:mod:`django.contrib.localflavor` contains assorted pieces of code
|
||||||
that are useful for particular countries or cultures. This data is
|
that are useful for particular countries or cultures. This data is
|
||||||
local in nature, and is subject to change on timelines that will
|
local in nature, and is subject to change on timelines that will
|
||||||
|
|
|
@ -87,16 +87,24 @@ YearArchiveView
|
||||||
* ``year``: A :class:`~datetime.date` object
|
* ``year``: A :class:`~datetime.date` object
|
||||||
representing the given year.
|
representing the given year.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.5
|
||||||
|
|
||||||
|
Previously, this returned a string.
|
||||||
|
|
||||||
* ``next_year``: A :class:`~datetime.date` object
|
* ``next_year``: A :class:`~datetime.date` object
|
||||||
representing the first day of the next year, according to
|
representing the first day of the next year, according to
|
||||||
:attr:`~BaseDateListView.allow_empty` and
|
:attr:`~BaseDateListView.allow_empty` and
|
||||||
:attr:`~DateMixin.allow_future`.
|
:attr:`~DateMixin.allow_future`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
|
||||||
* ``previous_year``: A :class:`~datetime.date` object
|
* ``previous_year``: A :class:`~datetime.date` object
|
||||||
representing the first day of the previous year, according to
|
representing the first day of the previous year, according to
|
||||||
:attr:`~BaseDateListView.allow_empty` and
|
:attr:`~BaseDateListView.allow_empty` and
|
||||||
:attr:`~DateMixin.allow_future`.
|
:attr:`~DateMixin.allow_future`.
|
||||||
|
|
||||||
|
.. versionadded:: 1.5
|
||||||
|
|
||||||
**Notes**
|
**Notes**
|
||||||
|
|
||||||
* Uses a default ``template_name_suffix`` of ``_archive_year``.
|
* Uses a default ``template_name_suffix`` of ``_archive_year``.
|
||||||
|
|
|
@ -318,12 +318,16 @@ BaseDateListView
|
||||||
Returns the aggregation period for ``date_list``. Returns
|
Returns the aggregation period for ``date_list``. Returns
|
||||||
:attr:`~BaseDateListView.date_list_period` by default.
|
: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``
|
Returns the list of dates of type ``date_type`` for which ``queryset``
|
||||||
contains entries. For example, ``get_date_list(qs, 'year')`` will
|
contains entries. For example, ``get_date_list(qs, 'year')`` will
|
||||||
return the list of years for which ``qs`` has entries. If
|
return the list of years for which ``qs`` has entries. If
|
||||||
``date_type`` isn't provided, the result of
|
``date_type`` isn't provided, the result of
|
||||||
:meth:`BaseDateListView.get_date_list_period` is used. See
|
:meth:`~BaseDateListView.get_date_list_period` is used. ``date_type``
|
||||||
:meth:`~django.db.models.query.QuerySet.dates()` for the ways that the
|
and ``ordering`` are simply passed to
|
||||||
``date_type`` argument can be used.
|
: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.
|
||||||
|
|
|
@ -129,8 +129,6 @@ subclass::
|
||||||
|
|
||||||
date_hierarchy = 'pub_date'
|
date_hierarchy = 'pub_date'
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
This will intelligently populate itself based on available data,
|
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
|
e.g. if all the dates are in one month, it'll show the day-level
|
||||||
drill-down only.
|
drill-down only.
|
||||||
|
@ -576,8 +574,6 @@ subclass::
|
||||||
class PersonAdmin(ModelAdmin):
|
class PersonAdmin(ModelAdmin):
|
||||||
list_filter = ('is_staff', 'company')
|
list_filter = ('is_staff', 'company')
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Field names in ``list_filter`` can also span relations
|
Field names in ``list_filter`` can also span relations
|
||||||
using the ``__`` lookup, for example::
|
using the ``__`` lookup, for example::
|
||||||
|
|
||||||
|
@ -748,8 +744,6 @@ subclass::
|
||||||
|
|
||||||
.. attribute:: ModelAdmin.paginator
|
.. attribute:: ModelAdmin.paginator
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The paginator class to be used for pagination. By default,
|
The paginator class to be used for pagination. By default,
|
||||||
:class:`django.core.paginator.Paginator` is used. If the custom paginator
|
:class:`django.core.paginator.Paginator` is used. If the custom paginator
|
||||||
class doesn't have the same constructor interface as
|
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)
|
.. method:: ModelAdmin.delete_model(self, request, obj)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The ``delete_model`` method is given the ``HttpRequest`` and a model
|
The ``delete_model`` method is given the ``HttpRequest`` and a model
|
||||||
instance. Use this method to do pre- or post-delete operations.
|
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)
|
.. 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,
|
Returns an instance of the paginator to use for this view. By default,
|
||||||
instantiates an instance of :attr:`paginator`.
|
instantiates an instance of :attr:`paginator`.
|
||||||
|
|
||||||
|
@ -1295,8 +1285,6 @@ on your ``ModelAdmin``::
|
||||||
}
|
}
|
||||||
js = ("my_code.js",)
|
js = ("my_code.js",)
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
The :doc:`staticfiles app </ref/contrib/staticfiles>` prepends
|
The :doc:`staticfiles app </ref/contrib/staticfiles>` prepends
|
||||||
:setting:`STATIC_URL` (or :setting:`MEDIA_URL` if :setting:`STATIC_URL` is
|
: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
|
``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.exclude`
|
||||||
- :attr:`~ModelAdmin.filter_horizontal`
|
- :attr:`~ModelAdmin.filter_horizontal`
|
||||||
- :attr:`~ModelAdmin.filter_vertical`
|
- :attr:`~ModelAdmin.filter_vertical`
|
||||||
|
- :attr:`~ModelAdmin.ordering`
|
||||||
- :attr:`~ModelAdmin.prepopulated_fields`
|
- :attr:`~ModelAdmin.prepopulated_fields`
|
||||||
|
- :meth:`~ModelAdmin.queryset`
|
||||||
- :attr:`~ModelAdmin.radio_fields`
|
- :attr:`~ModelAdmin.radio_fields`
|
||||||
- :attr:`~ModelAdmin.readonly_fields`
|
- :attr:`~ModelAdmin.readonly_fields`
|
||||||
- :attr:`~InlineModelAdmin.raw_id_fields`
|
- :attr:`~InlineModelAdmin.raw_id_fields`
|
||||||
- :meth:`~ModelAdmin.formfield_for_foreignkey`
|
- :meth:`~ModelAdmin.formfield_for_foreignkey`
|
||||||
- :meth:`~ModelAdmin.formfield_for_manytomany`
|
- :meth:`~ModelAdmin.formfield_for_manytomany`
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
- :attr:`~ModelAdmin.ordering`
|
|
||||||
- :meth:`~ModelAdmin.queryset`
|
|
||||||
|
|
||||||
.. versionadded:: 1.4
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
- :meth:`~ModelAdmin.has_add_permission`
|
- :meth:`~ModelAdmin.has_add_permission`
|
||||||
|
@ -1813,8 +1798,6 @@ Templates can override or extend base admin templates as described in
|
||||||
|
|
||||||
.. attribute:: AdminSite.login_form
|
.. attribute:: AdminSite.login_form
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Subclass of :class:`~django.contrib.auth.forms.AuthenticationForm` that
|
Subclass of :class:`~django.contrib.auth.forms.AuthenticationForm` that
|
||||||
will be used by the admin site login view.
|
will be used by the admin site login view.
|
||||||
|
|
||||||
|
|
|
@ -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/``.
|
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
|
Moderation
|
||||||
==========
|
==========
|
||||||
|
|
|
@ -136,10 +136,6 @@ Simply subclassing :class:`CommentModerator` and changing the values of these
|
||||||
options will automatically enable the various moderation methods for any
|
options will automatically enable the various moderation methods for any
|
||||||
models registered using the subclass.
|
models registered using the subclass.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
``moderate_after`` and ``close_after`` now accept 0 as a valid value.
|
|
||||||
|
|
||||||
Adding custom moderation methods
|
Adding custom moderation methods
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
if a ``Bookmark`` object were deleted, any ``TaggedItem`` objects pointing at
|
||||||
it would be deleted at the same time.
|
it would be deleted at the same time.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Unlike :class:`~django.db.models.ForeignKey`,
|
Unlike :class:`~django.db.models.ForeignKey`,
|
||||||
:class:`~django.contrib.contenttypes.generic.GenericForeignKey` does not accept
|
:class:`~django.contrib.contenttypes.generic.GenericForeignKey` does not accept
|
||||||
an :attr:`~django.db.models.ForeignKey.on_delete` argument to customize this
|
an :attr:`~django.db.models.ForeignKey.on_delete` argument to customize this
|
||||||
|
|
|
@ -239,8 +239,6 @@ template.
|
||||||
Getting a list of :class:`~django.contrib.flatpages.models.FlatPage` objects in your templates
|
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
|
The flatpages app provides a template tag that allows you to iterate
|
||||||
over all of the available flatpages on the :ref:`current site
|
over all of the available flatpages on the :ref:`current site
|
||||||
<hooking-into-current-site-from-views>`.
|
<hooking-into-current-site-from-views>`.
|
||||||
|
|
|
@ -45,7 +45,7 @@ GeoDjango's admin site
|
||||||
.. attribute:: openlayers_url
|
.. attribute:: openlayers_url
|
||||||
|
|
||||||
Link to the URL of the OpenLayers JavaScript. Defaults to
|
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
|
.. attribute:: modifiable
|
||||||
|
|
|
@ -163,6 +163,11 @@ WKB / EWKB ``buffer``
|
||||||
GeoJSON ``str`` or ``unicode``
|
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
|
Properties
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -232,8 +237,6 @@ Returns a boolean indicating whether the geometry is valid.
|
||||||
|
|
||||||
.. attribute:: GEOSGeometry.valid_reason
|
.. attribute:: GEOSGeometry.valid_reason
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Returns a string describing the reason why a geometry is invalid.
|
Returns a string describing the reason why a geometry is invalid.
|
||||||
|
|
||||||
.. attribute:: GEOSGeometry.srid
|
.. attribute:: GEOSGeometry.srid
|
||||||
|
@ -530,8 +533,6 @@ corresponding to the SRID of the geometry or ``None``.
|
||||||
|
|
||||||
.. method:: GEOSGeometry.transform(ct, clone=False)
|
.. method:: GEOSGeometry.transform(ct, clone=False)
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
Transforms the geometry according to the given coordinate transformation paramter
|
Transforms the geometry according to the given coordinate transformation paramter
|
||||||
(``ct``), which may be an integer SRID, spatial reference WKT string,
|
(``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
|
a PROJ.4 string, a :class:`~django.contrib.gis.gdal.SpatialReference` object, or a
|
||||||
|
|
|
@ -134,8 +134,6 @@ your settings::
|
||||||
GeoDjango tests
|
GeoDjango tests
|
||||||
===============
|
===============
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
GeoDjango's test suite may be run in one of two ways, either by itself or
|
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>`.
|
with the rest of :ref:`Django's unit tests <running-unit-tests>`.
|
||||||
|
|
||||||
|
|
|
@ -267,8 +267,6 @@ Austria (``at``)
|
||||||
Belgium (``be``)
|
Belgium (``be``)
|
||||||
================
|
================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. class:: be.forms.BEPhoneNumberField
|
.. class:: be.forms.BEPhoneNumberField
|
||||||
|
|
||||||
A form field that validates input as a Belgium phone number, with one of
|
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.
|
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
|
.. class:: id.forms.IDPhoneNumberField
|
||||||
|
|
||||||
A form field that validates input as an Indonesian telephone number.
|
A form field that validates input as an Indonesian telephone number.
|
||||||
|
|
|
@ -330,8 +330,6 @@ with a caching decorator -- you must name your sitemap view and pass
|
||||||
Template customization
|
Template customization
|
||||||
======================
|
======================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
If you wish to use a different template for each sitemap or sitemap index
|
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``
|
available on your site, you may specify it by passing a ``template_name``
|
||||||
parameter to the ``sitemap`` and ``index`` views via the URLconf::
|
parameter to the ``sitemap`` and ``index`` views via the URLconf::
|
||||||
|
|
|
@ -159,8 +159,6 @@ the :class:`~django.contrib.sites.models.Site` model's manager has a
|
||||||
else:
|
else:
|
||||||
# Do something else.
|
# Do something else.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
For code which relies on getting the current domain but cannot be certain
|
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
|
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
|
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
|
This allows loose coupling with the sites framework and provides a usable
|
||||||
fallback for cases where it is not installed.
|
fallback for cases where it is not installed.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. function:: get_current_site(request)
|
.. function:: get_current_site(request)
|
||||||
|
|
||||||
Checks if contrib.sites is installed and returns either the current
|
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
|
:class:`~django.contrib.sites.models.RequestSite` object based on
|
||||||
the request.
|
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
|
Sets the ``name`` and ``domain`` attributes to the value of
|
||||||
:meth:`~django.http.HttpRequest.get_host`.
|
:meth:`~django.http.HttpRequest.get_host`.
|
||||||
|
|
||||||
|
|
||||||
A :class:`~django.contrib.sites.models.RequestSite` object has a similar
|
A :class:`~django.contrib.sites.models.RequestSite` object has a similar
|
||||||
interface to a normal :class:`~django.contrib.sites.models.Site` object, except
|
interface to a normal :class:`~django.contrib.sites.models.Site` object, except
|
||||||
|
|
|
@ -5,8 +5,6 @@ The staticfiles app
|
||||||
.. module:: django.contrib.staticfiles
|
.. module:: django.contrib.staticfiles
|
||||||
:synopsis: An app for handling static files.
|
:synopsis: An app for handling static files.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``django.contrib.staticfiles`` collects static files from each of your
|
``django.contrib.staticfiles`` collects static files from each of your
|
||||||
applications (and any other places you specify) into a single location that
|
applications (and any other places you specify) into a single location that
|
||||||
can easily be served in production.
|
can easily be served in production.
|
||||||
|
|
|
@ -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
|
the default manager and it filters some of the available records, not all of the
|
||||||
objects will be dumped.
|
objects will be dumped.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The :djadminopt:`--all` option may be provided to specify that
|
The :djadminopt:`--all` option may be provided to specify that
|
||||||
``dumpdata`` should use Django's base manager, dumping records which
|
``dumpdata`` should use Django's base manager, dumping records which
|
||||||
might otherwise be filtered or modified by a custom manager.
|
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.
|
pretty-print the output with a number of indentation spaces.
|
||||||
|
|
||||||
The :djadminopt:`--exclude` option may be provided to prevent specific
|
The :djadminopt:`--exclude` option may be provided to prevent specific
|
||||||
applications from being dumped.
|
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
|
||||||
.. versionadded:: 1.3
|
will be restricted to that model, rather than the entire application. You can
|
||||||
|
also mix application names and model names.
|
||||||
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.
|
|
||||||
|
|
||||||
The :djadminopt:`--database` option can be used to specify the database
|
The :djadminopt:`--database` option can be used to specify the database
|
||||||
from which data will be dumped.
|
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
|
.. django-admin-option:: --no-wrap
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Use the ``--no-wrap`` option to disable breaking long message lines into
|
Use the ``--no-wrap`` option to disable breaking long message lines into
|
||||||
several lines in language files.
|
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
|
machines on the network, use its own IP address (e.g. ``192.168.2.1``) or
|
||||||
``0.0.0.0`` or ``::`` (with IPv6 enabled).
|
``0.0.0.0`` or ``::`` (with IPv6 enabled).
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
You can provide an IPv6 address surrounded by brackets
|
You can provide an IPv6 address surrounded by brackets
|
||||||
(e.g. ``[200a::1]:8000``). This will automatically enable IPv6 support.
|
(e.g. ``[200a::1]:8000``). This will automatically enable IPv6 support.
|
||||||
|
|
||||||
A hostname containing ASCII-only characters can also be used.
|
A hostname containing ASCII-only characters can also be used.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
If the :doc:`staticfiles</ref/contrib/staticfiles>` contrib app is enabled
|
If the :doc:`staticfiles</ref/contrib/staticfiles>` contrib app is enabled
|
||||||
(default in new projects) the :djadmin:`runserver` command will be overriden
|
(default in new projects) the :djadmin:`runserver` command will be overriden
|
||||||
with an own :djadmin:`runserver<staticfiles-runserver>` command.
|
with an own :djadmin:`runserver<staticfiles-runserver>` command.
|
||||||
|
@ -674,8 +658,6 @@ development server.
|
||||||
|
|
||||||
.. django-admin-option:: --ipv6, -6
|
.. django-admin-option:: --ipv6, -6
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Use the ``--ipv6`` (or shorter ``-6``) option to tell Django to use IPv6 for
|
Use the ``--ipv6`` (or shorter ``-6``) option to tell Django to use IPv6 for
|
||||||
the development server. This changes the default IP address from
|
the development server. This changes the default IP address from
|
||||||
``127.0.0.1`` to ``::1``.
|
``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
|
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
|
The :djadminopt:`--noinput` option may be provided to suppress all user
|
||||||
prompts.
|
prompts.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ Django provides two convenient ways to access the current storage class:
|
||||||
.. function:: get_storage_class([import_path=None])
|
.. function:: get_storage_class([import_path=None])
|
||||||
|
|
||||||
Returns a class or module which implements the storage API.
|
Returns a class or module which implements the storage API.
|
||||||
|
|
||||||
When called without the ``import_path`` parameter ``get_storage_class``
|
When called without the ``import_path`` parameter ``get_storage_class``
|
||||||
will return the current default storage system as defined by
|
will return the current default storage system as defined by
|
||||||
:setting:`DEFAULT_FILE_STORAGE`. If ``import_path`` is provided,
|
: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
|
basic file storage on a local filesystem. It inherits from
|
||||||
:class:`~django.core.files.storage.Storage` and provides implementations
|
:class:`~django.core.files.storage.Storage` and provides implementations
|
||||||
for all the public methods thereof.
|
for all the public methods thereof.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
The :class:`FileSystemStorage.delete` method will not raise
|
The :class:`FileSystemStorage.delete` method will not raise
|
||||||
raise an exception if the given file name does not exist.
|
raise an exception if the given file name does not exist.
|
||||||
|
|
||||||
|
@ -53,16 +53,12 @@ The Storage Class
|
||||||
|
|
||||||
.. method:: accessed_time(name)
|
.. method:: accessed_time(name)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Returns a ``datetime`` object containing the last accessed time of the
|
Returns a ``datetime`` object containing the last accessed time of the
|
||||||
file. For storage systems that aren't able to return the last accessed
|
file. For storage systems that aren't able to return the last accessed
|
||||||
time this will raise ``NotImplementedError`` instead.
|
time this will raise ``NotImplementedError`` instead.
|
||||||
|
|
||||||
.. method:: created_time(name)
|
.. method:: created_time(name)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Returns a ``datetime`` object containing the creation time of the file.
|
Returns a ``datetime`` object containing the creation time of the file.
|
||||||
For storage systems that aren't able to return the creation time this
|
For storage systems that aren't able to return the creation time this
|
||||||
will raise ``NotImplementedError`` instead.
|
will raise ``NotImplementedError`` instead.
|
||||||
|
@ -100,8 +96,6 @@ The Storage Class
|
||||||
|
|
||||||
.. method:: modified_time(name)
|
.. method:: modified_time(name)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Returns a ``datetime`` object containing the last modified time. For
|
Returns a ``datetime`` object containing the last modified time. For
|
||||||
storage systems that aren't able to return the last modified time, this
|
storage systems that aren't able to return the last modified time, this
|
||||||
will raise ``NotImplementedError`` instead.
|
will raise ``NotImplementedError`` instead.
|
||||||
|
|
|
@ -658,8 +658,6 @@ those classes as an argument::
|
||||||
|
|
||||||
.. method:: BoundField.value()
|
.. method:: BoundField.value()
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Use this method to render the raw value of this field as it would be rendered
|
Use this method to render the raw value of this field as it would be rendered
|
||||||
by a ``Widget``::
|
by a ``Widget``::
|
||||||
|
|
||||||
|
|
|
@ -704,8 +704,6 @@ For each field, we describe the default widget used if you don't specify
|
||||||
``TypedMultipleChoiceField``
|
``TypedMultipleChoiceField``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. class:: TypedMultipleChoiceField(**kwargs)
|
.. class:: TypedMultipleChoiceField(**kwargs)
|
||||||
|
|
||||||
Just like a :class:`MultipleChoiceField`, except :class:`TypedMultipleChoiceField`
|
Just like a :class:`MultipleChoiceField`, except :class:`TypedMultipleChoiceField`
|
||||||
|
|
|
@ -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
|
Determines whether the widget will have a value filled in when the
|
||||||
form is re-displayed after a validation error (default is ``False``).
|
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``
|
``HiddenInput``
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -532,8 +527,6 @@ File upload widgets
|
||||||
|
|
||||||
.. class:: ClearableFileInput
|
.. class:: ClearableFileInput
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
File upload input: ``<input type='file' ...>``, with an additional checkbox
|
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
|
input to clear the field's value, if the field is not required and has
|
||||||
initial data.
|
initial data.
|
||||||
|
|
|
@ -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
|
The field on the related object that the relation is to. By default, Django
|
||||||
uses the primary key of the related object.
|
uses the primary key of the related object.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. attribute:: ForeignKey.on_delete
|
.. attribute:: ForeignKey.on_delete
|
||||||
|
|
||||||
When an object referenced by a :class:`ForeignKey` is deleted, Django by
|
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
|
:class:`ForeignKey`, including all the options regarding :ref:`recursive
|
||||||
<recursive-relationships>` and :ref:`lazy <lazy-relationships>` relationships.
|
<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
|
Database Representation
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -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
|
but it doesn't really matter. This is your chance to really flaunt your
|
||||||
individualism.
|
individualism.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
You can also refer to fields on related models with reverse relations through
|
||||||
|
``OneToOneField``, ``ForeignKey`` and ``ManyToManyField`` attributes::
|
||||||
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::
|
|
||||||
|
|
||||||
Blog.objects.values('name', 'entry__headline')
|
Blog.objects.values('name', 'entry__headline')
|
||||||
[{'name': 'My blog', 'entry__headline': 'An entry'},
|
[{'name': 'My blog', 'entry__headline': 'An entry'},
|
||||||
|
@ -1664,10 +1657,9 @@ For example::
|
||||||
# This will delete all Blogs and all of their Entry objects.
|
# This will delete all Blogs and all of their Entry objects.
|
||||||
blogs.delete()
|
blogs.delete()
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
This cascade behavior is customizable via the
|
||||||
This cascade behavior is customizable via the
|
:attr:`~django.db.models.ForeignKey.on_delete` argument to the
|
||||||
:attr:`~django.db.models.ForeignKey.on_delete` argument to the
|
:class:`~django.db.models.ForeignKey`.
|
||||||
:class:`~django.db.models.ForeignKey`.
|
|
||||||
|
|
||||||
The ``delete()`` method does a bulk delete and does not call any ``delete()``
|
The ``delete()`` method does a bulk delete and does not call any ``delete()``
|
||||||
methods on your models. It does, however, emit the
|
methods on your models. It does, however, emit the
|
||||||
|
|
|
@ -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,
|
data in different ways than conventional HTML forms: binary images,
|
||||||
XML payload etc. For processing conventional form data, use ``HttpRequest.POST``.
|
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
|
You can also read from an HttpRequest using a file-like interface. See
|
||||||
:meth:`HttpRequest.read()`.
|
:meth:`HttpRequest.read()`.
|
||||||
|
|
||||||
|
@ -305,8 +303,6 @@ Methods
|
||||||
.. method:: HttpRequest.xreadlines()
|
.. method:: HttpRequest.xreadlines()
|
||||||
.. method:: HttpRequest.__iter__()
|
.. method:: HttpRequest.__iter__()
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Methods implementing a file-like interface for reading from an
|
Methods implementing a file-like interface for reading from an
|
||||||
HttpRequest instance. This makes it possible to consume an incoming
|
HttpRequest instance. This makes it possible to consume an incoming
|
||||||
request in a streaming fashion. A common use-case would be to process a
|
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()
|
>>> q.urlencode()
|
||||||
'a=2&b=3&b=5'
|
'a=2&b=3&b=5'
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
The ``safe`` parameter was added.
|
|
||||||
|
|
||||||
Optionally, urlencode can be passed characters which
|
Optionally, urlencode can be passed characters which
|
||||||
do not require encoding. For example::
|
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)
|
.. 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
|
.. versionchanged:: 1.4
|
||||||
|
|
||||||
The default value for httponly was changed from ``False`` to ``True``.
|
The default value for httponly was changed from ``False`` to ``True``.
|
||||||
|
|
|
@ -124,8 +124,6 @@ The model to use to represent a User. See :ref:`auth-custom-user`.
|
||||||
CACHES
|
CACHES
|
||||||
------
|
------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Default::
|
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
|
Writing a whole new cache backend from scratch is left as an exercise
|
||||||
to the reader; see the other backends for examples.
|
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
|
.. setting:: CACHES-KEY_FUNCTION
|
||||||
|
|
||||||
KEY_FUNCTION
|
KEY_FUNCTION
|
||||||
|
@ -533,8 +525,6 @@ Only supported for the ``mysql`` backend (see the `MySQL manual`_ for details).
|
||||||
TEST_DEPENDENCIES
|
TEST_DEPENDENCIES
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Default: ``['default']``, for all databases other than ``default``,
|
Default: ``['default']``, for all databases other than ``default``,
|
||||||
which has no dependencies.
|
which has no dependencies.
|
||||||
|
|
||||||
|
@ -1261,8 +1251,6 @@ the ``locale`` directory (i.e. ``'/path/to/locale'``).
|
||||||
LOGGING
|
LOGGING
|
||||||
-------
|
-------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Default: A logging configuration dictionary.
|
Default: A logging configuration dictionary.
|
||||||
|
|
||||||
A data structure containing configuration information. The contents of
|
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
|
LOGGING_CONFIG
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Default: ``'django.utils.log.dictConfig'``
|
Default: ``'django.utils.log.dictConfig'``
|
||||||
|
|
||||||
A path to a callable that will be used to configure logging in the
|
A path to a callable that will be used to configure logging in the
|
||||||
|
@ -1370,13 +1356,11 @@ MEDIA_URL
|
||||||
Default: ``''`` (Empty string)
|
Default: ``''`` (Empty string)
|
||||||
|
|
||||||
URL that handles the media served from :setting:`MEDIA_ROOT`, used
|
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/"``
|
Example: ``"http://media.example.com/"``
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
It must end in a slash if set to a non-empty value.
|
|
||||||
|
|
||||||
MESSAGE_LEVEL
|
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
|
These callables take a request object as their argument and return a dictionary
|
||||||
of items to be merged into the context.
|
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
|
.. versionadded:: 1.4
|
||||||
The ``django.core.context_processors.tz`` context processor
|
The ``django.core.context_processors.tz`` context processor
|
||||||
was added in this release.
|
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
|
USE_X_FORWARDED_HOST
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3.1
|
|
||||||
|
|
||||||
Default: ``False``
|
Default: ``False``
|
||||||
|
|
||||||
A boolean that specifies whether to use the X-Forwarded-Host header in
|
A boolean that specifies whether to use the X-Forwarded-Host header in
|
||||||
|
|
|
@ -46,7 +46,7 @@ pre_init
|
||||||
|
|
||||||
.. ^^^^^^^ this :module: hack keeps Sphinx from prepending the module.
|
.. ^^^^^^^ 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.
|
of the model's :meth:`~django.db.models.Model.__init__` method.
|
||||||
|
|
||||||
Arguments sent with this signal:
|
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
|
records in the database as the database might not be in a
|
||||||
consistent state yet.
|
consistent state yet.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``using``
|
``using``
|
||||||
The database alias being used.
|
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
|
records in the database as the database might not be in a
|
||||||
consistent state yet.
|
consistent state yet.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``using``
|
``using``
|
||||||
The database alias being used.
|
The database alias being used.
|
||||||
|
|
||||||
|
@ -183,8 +179,6 @@ Arguments sent with this signal:
|
||||||
``instance``
|
``instance``
|
||||||
The actual instance being deleted.
|
The actual instance being deleted.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``using``
|
``using``
|
||||||
The database alias being used.
|
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
|
Note that the object will no longer be in the database, so be very
|
||||||
careful what you do with this instance.
|
careful what you do with this instance.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``using``
|
``using``
|
||||||
The database alias being used.
|
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``.
|
For the ``pre_clear`` and ``post_clear`` actions, this is ``None``.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
``using``
|
``using``
|
||||||
The database alias being used.
|
The database alias being used.
|
||||||
|
|
||||||
|
@ -287,13 +277,22 @@ like this::
|
||||||
# ...
|
# ...
|
||||||
toppings = models.ManyToManyField(Topping)
|
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(...)
|
>>> p = Pizza.object.create(...)
|
||||||
>>> t = Topping.objects.create(...)
|
>>> t = Topping.objects.create(...)
|
||||||
>>> p.toppings.add(t)
|
>>> 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
|
Argument Value
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
TemplateResponse and SimpleTemplateResponse
|
TemplateResponse and SimpleTemplateResponse
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. module:: django.template.response
|
.. module:: django.template.response
|
||||||
:synopsis: Classes dealing with lazy-rendered HTTP responses.
|
:synopsis: Classes dealing with lazy-rendered HTTP responses.
|
||||||
|
|
||||||
|
|
|
@ -160,11 +160,6 @@ it. Example::
|
||||||
>>> t.render(Context({"person": PersonClass2}))
|
>>> t.render(Context({"person": PersonClass2}))
|
||||||
"My name is Samantha."
|
"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
|
Callable variables are slightly more complex than variables which only require
|
||||||
straight lookups. Here are some things to keep in mind:
|
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
|
``django.contrib.auth.context_processors.PermWrapper``, representing the
|
||||||
permissions that the currently logged-in user has.
|
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
|
django.core.context_processors.debug
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -491,8 +481,6 @@ django.core.context_processors.static
|
||||||
|
|
||||||
.. function:: django.core.context_processors.static
|
.. function:: django.core.context_processors.static
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
||||||
``RequestContext`` will contain a variable ``STATIC_URL``, providing the
|
``RequestContext`` will contain a variable ``STATIC_URL``, providing the
|
||||||
value of the :setting:`STATIC_URL` setting.
|
value of the :setting:`STATIC_URL` setting.
|
||||||
|
|
|
@ -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
|
way to specify variable values. Or literal commas. Or spaces. Did we mention
|
||||||
you shouldn't use this syntax in any new projects?
|
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
|
By default, when you use the ``as`` keyword with the cycle tag, the
|
||||||
usage of ``{% cycle %}`` that declares the cycle will itself output
|
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
|
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" }}!
|
{{ greeting }}, {{ person|default:"friend" }}!
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Additional context and exclusive context.
|
|
||||||
|
|
||||||
You can pass additional context to the template using keyword arguments::
|
You can pass additional context to the template using keyword arguments::
|
||||||
|
|
||||||
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}
|
{% 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 %}
|
{% load somelibrary package.otherlibrary %}
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
You can also selectively load individual filters or tags from a library, using
|
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``
|
the ``from`` argument. In this example, the template tags/filters named ``foo``
|
||||||
and ``bar`` will be loaded from ``somelibrary``::
|
and ``bar`` will be loaded from ``somelibrary``::
|
||||||
|
@ -1076,9 +1069,6 @@ which is rounded up to 88).
|
||||||
with
|
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
|
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.
|
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.
|
month, 2 characters.
|
||||||
t Number of days in the given month. ``28`` to ``31``
|
t Number of days in the given month. ``28`` to ``31``
|
||||||
T Time zone of this machine. ``'EST'``, ``'MDT'``
|
T Time zone of this machine. ``'EST'``, ``'MDT'``
|
||||||
u Microseconds. ``0`` to ``999999``
|
u Microseconds. ``000000`` to ``999999``
|
||||||
U Seconds since the Unix Epoch
|
U Seconds since the Unix Epoch
|
||||||
(January 1 1970 00:00:00 UTC).
|
(January 1 1970 00:00:00 UTC).
|
||||||
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
|
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
|
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"``.
|
``"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
|
An optional argument containing the characters which should not be escaped can
|
||||||
be provided.
|
be provided.
|
||||||
|
|
||||||
|
|
|
@ -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
|
* The :ref:`receiver <connecting-receiver-functions>` decorator is now able to
|
||||||
connect to more than one signal by supplying a list of signals.
|
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()
|
* :meth:`QuerySet.bulk_create()
|
||||||
<django.db.models.query.QuerySet.bulk_create>` now has a batch_size
|
<django.db.models.query.QuerySet.bulk_create>` now has a batch_size
|
||||||
argument. By default the batch_size is unlimited except for SQLite where
|
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
|
``next_year`` and ``previous_year`` were also added in the context. They are
|
||||||
calculated according to ``allow_empty`` and ``allow_future``.
|
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
|
Context in TemplateView
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -362,6 +379,11 @@ Miscellaneous
|
||||||
function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is
|
function at :func:`django.utils.text.slugify`. Similarly, ``remove_tags`` is
|
||||||
available at :func:`django.utils.html.remove_tags`.
|
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
|
Features deprecated in 1.5
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|
|
@ -872,8 +872,6 @@ How to log a user out
|
||||||
Login and logout signals
|
Login and logout signals
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The auth framework uses two :doc:`signals </topics/signals>` that can be used
|
The auth framework uses two :doc:`signals </topics/signals>` that can be used
|
||||||
for notification when a user logs in or out.
|
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
|
context variable which stores the redirect path will use the value of
|
||||||
``redirect_field_name`` as its key rather than ``"next"`` (the default).
|
``redirect_field_name`` as its key rather than ``"next"`` (the default).
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
:func:`~django.contrib.auth.decorators.login_required` also takes an
|
:func:`~django.contrib.auth.decorators.login_required` also takes an
|
||||||
optional ``login_url`` parameter. Example::
|
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
|
that can be used to reset the password, and sending that link to the
|
||||||
user's registered email address.
|
user's registered email address.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
The ``from_email`` argument was added.
|
|
||||||
|
|
||||||
.. versionchanged:: 1.4
|
.. versionchanged:: 1.4
|
||||||
Users flagged with an unusable password (see
|
Users flagged with an unusable password (see
|
||||||
:meth:`~django.contrib.auth.models.User.set_unusable_password()`
|
:meth:`~django.contrib.auth.models.User.set_unusable_password()`
|
||||||
|
@ -1684,10 +1677,6 @@ The currently logged-in user's permissions are stored in the template variable
|
||||||
:class:`django.contrib.auth.context_processors.PermWrapper`, which is a
|
:class:`django.contrib.auth.context_processors.PermWrapper`, which is a
|
||||||
template-friendly proxy of permissions.
|
template-friendly proxy of permissions.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Prior to version 1.3, ``PermWrapper`` was located in
|
|
||||||
``django.core.context_processors``.
|
|
||||||
|
|
||||||
In the ``{{ perms }}`` object, single-attribute lookup is a proxy to
|
In the ``{{ perms }}`` object, single-attribute lookup is a proxy to
|
||||||
:meth:`User.has_module_perms <django.contrib.auth.models.User.has_module_perms>`.
|
:meth:`User.has_module_perms <django.contrib.auth.models.User.has_module_perms>`.
|
||||||
This example would display ``True`` if the logged-in user had any permissions
|
This example would display ``True`` if the logged-in user had any permissions
|
||||||
|
@ -2263,8 +2252,6 @@ for example, to control anonymous access.
|
||||||
Authorization for inactive users
|
Authorization for inactive users
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
An inactive user is a one that is authenticated but has its attribute
|
An inactive user is a one that is authenticated but has its attribute
|
||||||
``is_active`` set to ``False``. However this does not mean they are not
|
``is_active`` set to ``False``. However this does not mean they are not
|
||||||
authorized to do anything. For example they are allowed to activate their
|
authorized to do anything. For example they are allowed to activate their
|
||||||
|
|
|
@ -51,13 +51,6 @@ Your cache preference goes in the :setting:`CACHES` setting in your
|
||||||
settings file. Here's an explanation of all available values for
|
settings file. Here's an explanation of all available values for
|
||||||
:setting:`CACHES`.
|
:setting:`CACHES`.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
The settings used to configure caching changed in Django 1.3. In
|
|
||||||
Django 1.2 and earlier, you used a single string-based
|
|
||||||
:setting:`CACHE_BACKEND` setting to configure caches. This has
|
|
||||||
been replaced with the new dictionary-based :setting:`CACHES`
|
|
||||||
setting.
|
|
||||||
|
|
||||||
.. _memcached:
|
.. _memcached:
|
||||||
|
|
||||||
Memcached
|
Memcached
|
||||||
|
@ -83,9 +76,6 @@ two most common are `python-memcached`_ and `pylibmc`_.
|
||||||
.. _`python-memcached`: ftp://ftp.tummy.com/pub/python-memcached/
|
.. _`python-memcached`: ftp://ftp.tummy.com/pub/python-memcached/
|
||||||
.. _`pylibmc`: http://sendapatch.se/projects/pylibmc/
|
.. _`pylibmc`: http://sendapatch.se/projects/pylibmc/
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Support for ``pylibmc`` was added.
|
|
||||||
|
|
||||||
To use Memcached with Django:
|
To use Memcached with Django:
|
||||||
|
|
||||||
* Set :setting:`BACKEND <CACHES-BACKEND>` to
|
* Set :setting:`BACKEND <CACHES-BACKEND>` to
|
||||||
|
@ -673,12 +663,27 @@ dictionaries, lists of model objects, and so forth. (Most common Python objects
|
||||||
can be pickled; refer to the Python documentation for more information about
|
can be pickled; refer to the Python documentation for more information about
|
||||||
pickling.)
|
pickling.)
|
||||||
|
|
||||||
|
Accessing the cache
|
||||||
|
-------------------
|
||||||
|
|
||||||
The cache module, ``django.core.cache``, has a ``cache`` object that's
|
The cache module, ``django.core.cache``, has a ``cache`` object that's
|
||||||
automatically created from the ``'default'`` entry in the :setting:`CACHES`
|
automatically created from the ``'default'`` entry in the :setting:`CACHES`
|
||||||
setting::
|
setting::
|
||||||
|
|
||||||
>>> from django.core.cache import cache
|
>>> from django.core.cache import cache
|
||||||
|
|
||||||
|
If you have multiple caches defined in :setting:`CACHES`, then you can use
|
||||||
|
:func:`django.core.cache.get_cache` to retrieve a cache object for any key::
|
||||||
|
|
||||||
|
>>> from django.core.cache import get_cache
|
||||||
|
>>> cache = get_cache('alternate')
|
||||||
|
|
||||||
|
If the named key does not exist, :exc:`InvalidCacheBackendError` will be raised.
|
||||||
|
|
||||||
|
|
||||||
|
Basic usage
|
||||||
|
-----------
|
||||||
|
|
||||||
The basic interface is ``set(key, value, timeout)`` and ``get(key)``::
|
The basic interface is ``set(key, value, timeout)`` and ``get(key)``::
|
||||||
|
|
||||||
>>> cache.set('my_key', 'hello, world!', 30)
|
>>> cache.set('my_key', 'hello, world!', 30)
|
||||||
|
@ -686,7 +691,7 @@ The basic interface is ``set(key, value, timeout)`` and ``get(key)``::
|
||||||
'hello, world!'
|
'hello, world!'
|
||||||
|
|
||||||
The ``timeout`` argument is optional and defaults to the ``timeout``
|
The ``timeout`` argument is optional and defaults to the ``timeout``
|
||||||
argument of the ``'default'`` backend in :setting:`CACHES` setting
|
argument of the appropriate backend in the :setting:`CACHES` setting
|
||||||
(explained above). It's the number of seconds the value should be stored
|
(explained above). It's the number of seconds the value should be stored
|
||||||
in the cache.
|
in the cache.
|
||||||
|
|
||||||
|
@ -785,8 +790,6 @@ nonexistent cache key.::
|
||||||
Cache key prefixing
|
Cache key prefixing
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
If you are sharing a cache instance between servers, or between your
|
If you are sharing a cache instance between servers, or between your
|
||||||
production and development environments, it's possible for data cached
|
production and development environments, it's possible for data cached
|
||||||
by one server to be used by another server. If the format of cached
|
by one server to be used by another server. If the format of cached
|
||||||
|
@ -807,8 +810,6 @@ collisions in cache values.
|
||||||
Cache versioning
|
Cache versioning
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
When you change running code that uses cached values, you may need to
|
When you change running code that uses cached values, you may need to
|
||||||
purge any existing cached values. The easiest way to do this is to
|
purge any existing cached values. The easiest way to do this is to
|
||||||
flush the entire cache, but this can lead to the loss of cache values
|
flush the entire cache, but this can lead to the loss of cache values
|
||||||
|
@ -856,8 +857,6 @@ keys unaffected. Continuing our previous example::
|
||||||
Cache key transformation
|
Cache key transformation
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
As described in the previous two sections, the cache key provided by a
|
As described in the previous two sections, the cache key provided by a
|
||||||
user is not used verbatim -- it is combined with the cache prefix and
|
user is not used verbatim -- it is combined with the cache prefix and
|
||||||
key version to provide a final cache key. By default, the three parts
|
key version to provide a final cache key. By default, the three parts
|
||||||
|
@ -878,8 +877,6 @@ be used instead of the default key combining function.
|
||||||
Cache key warnings
|
Cache key warnings
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Memcached, the most commonly-used production cache backend, does not allow
|
Memcached, the most commonly-used production cache backend, does not allow
|
||||||
cache keys longer than 250 characters or containing whitespace or control
|
cache keys longer than 250 characters or containing whitespace or control
|
||||||
characters, and using such keys will cause an exception. To encourage
|
characters, and using such keys will cause an exception. To encourage
|
||||||
|
@ -966,10 +963,6 @@ mechanism should take into account when building its cache key. For example, if
|
||||||
the contents of a Web page depend on a user's language preference, the page is
|
the contents of a Web page depend on a user's language preference, the page is
|
||||||
said to "vary on language."
|
said to "vary on language."
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
In Django 1.3 the full request path -- including the query -- is used
|
|
||||||
to create the cache keys, instead of only the path component in Django 1.2.
|
|
||||||
|
|
||||||
By default, Django's cache system creates its cache keys using the requested
|
By default, Django's cache system creates its cache keys using the requested
|
||||||
path and query -- e.g., ``"/stories/2005/?order_by=author"``. This means every
|
path and query -- e.g., ``"/stories/2005/?order_by=author"``. This means every
|
||||||
request to that URL will use the same cached version, regardless of user-agent
|
request to that URL will use the same cached version, regardless of user-agent
|
||||||
|
|
|
@ -4,11 +4,6 @@
|
||||||
Class-based generic views
|
Class-based generic views
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
.. note::
|
|
||||||
Prior to Django 1.3, generic views were implemented as functions. The
|
|
||||||
function-based implementation has been removed in favor of the
|
|
||||||
class-based approach described here.
|
|
||||||
|
|
||||||
Writing Web applications can be monotonous, because we repeat certain patterns
|
Writing Web applications can be monotonous, because we repeat certain patterns
|
||||||
again and again. Django tries to take away some of that monotony at the model
|
again and again. Django tries to take away some of that monotony at the model
|
||||||
and template layers, but Web developers also experience this boredom at the view
|
and template layers, but Web developers also experience this boredom at the view
|
||||||
|
|
|
@ -203,3 +203,43 @@ Note that you'll need to :ref:`decorate this
|
||||||
view<decorating-class-based-views>` using
|
view<decorating-class-based-views>` using
|
||||||
:func:`~django.contrib.auth.decorators.login_required`, or
|
:func:`~django.contrib.auth.decorators.login_required`, or
|
||||||
alternatively handle unauthorised users in the :meth:`form_valid()`.
|
alternatively handle unauthorised users in the :meth:`form_valid()`.
|
||||||
|
|
||||||
|
AJAX example
|
||||||
|
------------
|
||||||
|
|
||||||
|
Here is a simple example showing how you might go about implementing a form that
|
||||||
|
works for AJAX requests as well as 'normal' form POSTs::
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.views.generic.edit import CreateView
|
||||||
|
from django.views.generic.detail import SingleObjectTemplateResponseMixin
|
||||||
|
|
||||||
|
class AjaxableResponseMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin to add AJAX support to a form.
|
||||||
|
Must be used with an object-based FormView (e.g. CreateView)
|
||||||
|
"""
|
||||||
|
def render_to_json_response(self, context, **response_kwargs):
|
||||||
|
data = json.dumps(context)
|
||||||
|
response_kwargs['content_type'] = 'application/json'
|
||||||
|
return HttpResponse(data, **response_kwargs)
|
||||||
|
|
||||||
|
def form_invalid(self, form):
|
||||||
|
if self.request.is_ajax():
|
||||||
|
return self.render_to_json_response(form.errors, status=400)
|
||||||
|
else:
|
||||||
|
return super(AjaxableResponseMixin, self).form_invalid(form)
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
if self.request.is_ajax():
|
||||||
|
data = {
|
||||||
|
'pk': form.instance.pk,
|
||||||
|
}
|
||||||
|
return self.render_to_json_response(data)
|
||||||
|
else:
|
||||||
|
return super(AjaxableResponseMixin, self).form_valid(form)
|
||||||
|
|
||||||
|
class AuthorCreate(AjaxableResponseMixin, CreateView):
|
||||||
|
model = Author
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
Class-based views
|
Class-based views
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
A view is a callable which takes a request and returns a
|
A view is a callable which takes a request and returns a
|
||||||
response. This can be more than just a function, and Django provides
|
response. This can be more than just a function, and Django provides
|
||||||
an example of some classes which can be used as views. These allow you
|
an example of some classes which can be used as views. These allow you
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
Using mixins with class-based views
|
Using mixins with class-based views
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. caution::
|
.. caution::
|
||||||
|
|
||||||
This is an advanced topic. A working knowledge of :doc:`Django's
|
This is an advanced topic. A working knowledge of :doc:`Django's
|
||||||
|
|
|
@ -633,8 +633,6 @@ issue the query::
|
||||||
|
|
||||||
>>> Entry.objects.filter(authors__name=F('blog__name'))
|
>>> Entry.objects.filter(authors__name=F('blog__name'))
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
For date and date/time fields, you can add or subtract a
|
For date and date/time fields, you can add or subtract a
|
||||||
:class:`~datetime.timedelta` object. The following would return all entries
|
:class:`~datetime.timedelta` object. The following would return all entries
|
||||||
that were modified more than 3 days after they were published::
|
that were modified more than 3 days after they were published::
|
||||||
|
@ -876,7 +874,6 @@ it. For example::
|
||||||
# This will delete the Blog and all of its Entry objects.
|
# This will delete the Blog and all of its Entry objects.
|
||||||
b.delete()
|
b.delete()
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
This cascade behavior is customizable via the
|
This cascade behavior is customizable via the
|
||||||
:attr:`~django.db.models.ForeignKey.on_delete` argument to the
|
:attr:`~django.db.models.ForeignKey.on_delete` argument to the
|
||||||
:class:`~django.db.models.ForeignKey`.
|
:class:`~django.db.models.ForeignKey`.
|
||||||
|
|
|
@ -242,7 +242,7 @@ By default, the Python DB API will return results without their field
|
||||||
names, which means you end up with a ``list`` of values, rather than a
|
names, which means you end up with a ``list`` of values, rather than a
|
||||||
``dict``. At a small performance cost, you can return results as a
|
``dict``. At a small performance cost, you can return results as a
|
||||||
``dict`` by using something like this::
|
``dict`` by using something like this::
|
||||||
|
|
||||||
def dictfetchall(cursor):
|
def dictfetchall(cursor):
|
||||||
"Returns all rows from a cursor as a dict"
|
"Returns all rows from a cursor as a dict"
|
||||||
desc = cursor.description
|
desc = cursor.description
|
||||||
|
@ -256,7 +256,7 @@ Here is an example of the difference between the two::
|
||||||
>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
|
>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
|
||||||
>>> cursor.fetchall()
|
>>> cursor.fetchall()
|
||||||
((54360982L, None), (54360880L, None))
|
((54360982L, None), (54360880L, None))
|
||||||
|
|
||||||
>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
|
>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
|
||||||
>>> dictfetchall(cursor)
|
>>> dictfetchall(cursor)
|
||||||
[{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}]
|
[{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}]
|
||||||
|
@ -273,11 +273,6 @@ transaction containing those calls is closed correctly. See :ref:`the
|
||||||
notes on the requirements of Django's transaction handling
|
notes on the requirements of Django's transaction handling
|
||||||
<topics-db-transactions-requirements>` for more details.
|
<topics-db-transactions-requirements>` for more details.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
Prior to Django 1.3, it was necessary to manually mark a transaction
|
|
||||||
as dirty using ``transaction.set_dirty()`` when using raw SQL calls.
|
|
||||||
|
|
||||||
Connections and cursors
|
Connections and cursors
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,6 @@ database cursor (which is mapped to its own database connection internally).
|
||||||
Controlling transaction management in views
|
Controlling transaction management in views
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Transaction management context managers are new in Django 1.3.
|
|
||||||
|
|
||||||
For most people, implicit request-based transactions work wonderfully. However,
|
For most people, implicit request-based transactions work wonderfully. However,
|
||||||
if you need more fine-grained control over how transactions are managed, you can
|
if you need more fine-grained control over how transactions are managed, you can
|
||||||
use a set of functions in ``django.db.transaction`` to control transactions on a
|
use a set of functions in ``django.db.transaction`` to control transactions on a
|
||||||
|
@ -195,8 +192,6 @@ managers, too.
|
||||||
Requirements for transaction handling
|
Requirements for transaction handling
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Django requires that every transaction that is opened is closed before
|
Django requires that every transaction that is opened is closed before
|
||||||
the completion of a request. If you are using :func:`autocommit` (the
|
the completion of a request. If you are using :func:`autocommit` (the
|
||||||
default commit mode) or :func:`commit_on_success`, this will be done
|
default commit mode) or :func:`commit_on_success`, this will be done
|
||||||
|
|
|
@ -119,8 +119,6 @@ The "From:" header of the email will be the value of the
|
||||||
|
|
||||||
This method exists for convenience and readability.
|
This method exists for convenience and readability.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
If ``html_message`` is provided, the resulting email will be a
|
If ``html_message`` is provided, the resulting email will be a
|
||||||
:mimetype:`multipart/alternative` email with ``message`` as the
|
:mimetype:`multipart/alternative` email with ``message`` as the
|
||||||
:mimetype:`text/plain` content type and ``html_message`` as the
|
:mimetype:`text/plain` content type and ``html_message`` as the
|
||||||
|
@ -236,9 +234,6 @@ following parameters (in the given order, if positional arguments are used).
|
||||||
All parameters are optional and can be set at any time prior to calling the
|
All parameters are optional and can be set at any time prior to calling the
|
||||||
``send()`` method.
|
``send()`` method.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
The ``cc`` argument was added.
|
|
||||||
|
|
||||||
* ``subject``: The subject line of the email.
|
* ``subject``: The subject line of the email.
|
||||||
|
|
||||||
* ``body``: The body text. This should be a plain text message.
|
* ``body``: The body text. This should be a plain text message.
|
||||||
|
|
|
@ -35,19 +35,9 @@ display two blank forms::
|
||||||
|
|
||||||
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
|
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
Iterating over the ``formset`` will render the forms in the order they were
|
||||||
|
created. You can change this order by providing an alternate implementation for
|
||||||
Prior to Django 1.3, formset instances were not iterable. To render
|
the :meth:`__iter__()` method.
|
||||||
the formset you iterated over the ``forms`` attribute::
|
|
||||||
|
|
||||||
>>> formset = ArticleFormSet()
|
|
||||||
>>> for form in formset.forms:
|
|
||||||
... print(form.as_table())
|
|
||||||
|
|
||||||
Iterating over ``formset.forms`` will render the forms in the order
|
|
||||||
they were created. The default formset iterator also renders the forms
|
|
||||||
in this order, but you can change this order by providing an alternate
|
|
||||||
implementation for the :meth:`__iter__()` method.
|
|
||||||
|
|
||||||
Formsets can also be indexed into, which returns the corresponding form. If you
|
Formsets can also be indexed into, which returns the corresponding form. If you
|
||||||
override ``__iter__``, you will need to also override ``__getitem__`` to have
|
override ``__iter__``, you will need to also override ``__getitem__`` to have
|
||||||
|
|
|
@ -195,8 +195,6 @@ return values for dynamic media properties.
|
||||||
Paths in media definitions
|
Paths in media definitions
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
Paths used to specify media can be either relative or absolute. If a path
|
Paths used to specify media can be either relative or absolute. If a path
|
||||||
starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an
|
starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an
|
||||||
absolute path, and left as-is. All other paths will be prepended with the value
|
absolute path, and left as-is. All other paths will be prepended with the value
|
||||||
|
|
|
@ -117,8 +117,6 @@ middleware is always called on every response.
|
||||||
``process_template_response``
|
``process_template_response``
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. method:: process_template_response(self, request, response)
|
.. method:: process_template_response(self, request, response)
|
||||||
|
|
||||||
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a
|
``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is a
|
||||||
|
|
|
@ -17,8 +17,6 @@ introduce controlled coupling for convenience's sake.
|
||||||
|
|
||||||
.. function:: render(request, template_name[, dictionary][, context_instance][, content_type][, status][, current_app])
|
.. function:: render(request, template_name[, dictionary][, context_instance][, content_type][, status][, current_app])
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Combines a given template with a given context dictionary and returns an
|
Combines a given template with a given context dictionary and returns an
|
||||||
:class:`~django.http.HttpResponse` object with that rendered text.
|
:class:`~django.http.HttpResponse` object with that rendered text.
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,8 @@ algorithm the system follows to determine which Python code to execute:
|
||||||
one that matches the requested URL.
|
one that matches the requested URL.
|
||||||
|
|
||||||
4. Once one of the regexes matches, Django imports and calls the given
|
4. Once one of the regexes matches, Django imports and calls the given
|
||||||
view, which is a simple Python function. The view gets passed an
|
view, which is a simple Python function (or a :doc:`class based view
|
||||||
|
</topics/class-based-views/index>`). The view gets passed an
|
||||||
:class:`~django.http.HttpRequest` as its first argument and any values
|
:class:`~django.http.HttpRequest` as its first argument and any values
|
||||||
captured in the regex as remaining arguments.
|
captured in the regex as remaining arguments.
|
||||||
|
|
||||||
|
@ -673,6 +674,15 @@ The style you use is up to you.
|
||||||
Note that if you use this technique -- passing objects rather than strings --
|
Note that if you use this technique -- passing objects rather than strings --
|
||||||
the view prefix (as explained in "The view prefix" above) will have no effect.
|
the view prefix (as explained in "The view prefix" above) will have no effect.
|
||||||
|
|
||||||
|
Note that :doc:`class based views</topics/class-based-views/index>` must be
|
||||||
|
imported::
|
||||||
|
|
||||||
|
from mysite.views import ClassBasedView
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
(r'^myview/$', ClassBasedView.as_view()),
|
||||||
|
)
|
||||||
|
|
||||||
.. _naming-url-patterns:
|
.. _naming-url-patterns:
|
||||||
|
|
||||||
Naming URL patterns
|
Naming URL patterns
|
||||||
|
@ -970,13 +980,6 @@ A :class:`ResolverMatch` object can also be assigned to a triple::
|
||||||
|
|
||||||
func, args, kwargs = resolve('/some/path/')
|
func, args, kwargs = resolve('/some/path/')
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Triple-assignment exists for backwards-compatibility. Prior to
|
|
||||||
Django 1.3, :func:`~django.core.urlresolvers.resolve` returned a
|
|
||||||
triple containing (view function, arguments, keyword arguments);
|
|
||||||
the :class:`ResolverMatch` object (as well as the namespace and pattern
|
|
||||||
information it provides) is not available in earlier Django releases.
|
|
||||||
|
|
||||||
One possible use of :func:`~django.core.urlresolvers.resolve` would be to test
|
One possible use of :func:`~django.core.urlresolvers.resolve` would be to test
|
||||||
whether a view would raise a ``Http404`` error before redirecting to it::
|
whether a view would raise a ``Http404`` error before redirecting to it::
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,6 @@ Template tags
|
||||||
localize
|
localize
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Enables or disables localization of template variables in the
|
Enables or disables localization of template variables in the
|
||||||
contained block.
|
contained block.
|
||||||
|
|
||||||
|
@ -116,8 +114,6 @@ Template filters
|
||||||
localize
|
localize
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Forces localization of a single value.
|
Forces localization of a single value.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
@ -136,8 +132,6 @@ tag.
|
||||||
unlocalize
|
unlocalize
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Forces a single value to be printed without localization.
|
Forces a single value to be printed without localization.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
|
@ -134,8 +134,6 @@ translations wouldn't be able to reorder placeholder text.
|
||||||
Comments for translators
|
Comments for translators
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
If you would like to give translators hints about a translatable string, you
|
If you would like to give translators hints about a translatable string, you
|
||||||
can add a comment prefixed with the ``Translators`` keyword on the line
|
can add a comment prefixed with the ``Translators`` keyword on the line
|
||||||
preceding the string, e.g.::
|
preceding the string, e.g.::
|
||||||
|
@ -255,8 +253,6 @@ cardinality of the elements at play.
|
||||||
Contextual markers
|
Contextual markers
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Sometimes words have several meanings, such as ``"May"`` in English, which
|
Sometimes words have several meanings, such as ``"May"`` in English, which
|
||||||
refers to a month name and to a verb. To enable translators to translate
|
refers to a month name and to a verb. To enable translators to translate
|
||||||
these words correctly in different contexts, you can use the
|
these words correctly in different contexts, you can use the
|
||||||
|
@ -436,8 +432,6 @@ Localized names of languages
|
||||||
|
|
||||||
.. function:: get_language_info
|
.. function:: get_language_info
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The ``get_language_info()`` function provides detailed information about
|
The ``get_language_info()`` function provides detailed information about
|
||||||
languages::
|
languages::
|
||||||
|
|
||||||
|
@ -535,9 +529,6 @@ using the ``context`` keyword:
|
||||||
``blocktrans`` template tag
|
``blocktrans`` template tag
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
New keyword argument format.
|
|
||||||
|
|
||||||
Contrarily to the :ttag:`trans` tag, the ``blocktrans`` tag allows you to mark
|
Contrarily to the :ttag:`trans` tag, the ``blocktrans`` tag allows you to mark
|
||||||
complex sentences consisting of literals and variable content for translation
|
complex sentences consisting of literals and variable content for translation
|
||||||
by making use of placeholders::
|
by making use of placeholders::
|
||||||
|
@ -664,8 +655,6 @@ string, so they don't need to be aware of translations.
|
||||||
translator might translate the string ``"yes,no"`` as ``"ja,nein"``
|
translator might translate the string ``"yes,no"`` as ``"ja,nein"``
|
||||||
(keeping the comma intact).
|
(keeping the comma intact).
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
You can also retrieve information about any of the available languages using
|
You can also retrieve information about any of the available languages using
|
||||||
provided template tags and filters. To get information about a single language,
|
provided template tags and filters. To get information about a single language,
|
||||||
use the ``{% get_language_info %}`` tag::
|
use the ``{% get_language_info %}`` tag::
|
||||||
|
@ -787,10 +776,6 @@ directories listed in :setting:`LOCALE_PATHS` have the highest precedence with
|
||||||
the ones appearing first having higher precedence than the ones appearing
|
the ones appearing first having higher precedence than the ones appearing
|
||||||
later.
|
later.
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
Directories listed in :setting:`LOCALE_PATHS` weren't included in the
|
|
||||||
lookup algorithm until version 1.3.
|
|
||||||
|
|
||||||
Using the JavaScript translation catalog
|
Using the JavaScript translation catalog
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
Logging
|
Logging
|
||||||
=======
|
=======
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. module:: django.utils.log
|
.. module:: django.utils.log
|
||||||
:synopsis: Logging tools for Django applications
|
:synopsis: Logging tools for Django applications
|
||||||
|
|
||||||
|
|
|
@ -132,10 +132,6 @@ Now, our ``my_callback`` function will be called each time a request finishes.
|
||||||
Note that ``receiver`` can also take a list of signals to connect a function
|
Note that ``receiver`` can also take a list of signals to connect a function
|
||||||
to.
|
to.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The ``receiver`` decorator was added in Django 1.3.
|
|
||||||
|
|
||||||
.. versionchanged:: 1.5
|
.. versionchanged:: 1.5
|
||||||
|
|
||||||
The ability to pass a list of signals was added.
|
The ability to pass a list of signals was added.
|
||||||
|
|
|
@ -73,8 +73,6 @@ module defines tests in class-based approach.
|
||||||
|
|
||||||
.. admonition:: unittest2
|
.. admonition:: unittest2
|
||||||
|
|
||||||
.. versionchanged:: 1.3
|
|
||||||
|
|
||||||
Python 2.7 introduced some major changes to the unittest library,
|
Python 2.7 introduced some major changes to the unittest library,
|
||||||
adding some extremely useful features. To ensure that every Django
|
adding some extremely useful features. To ensure that every Django
|
||||||
project can benefit from these new features, Django ships with a
|
project can benefit from these new features, Django ships with a
|
||||||
|
@ -436,8 +434,6 @@ two databases.
|
||||||
Controlling creation order for test databases
|
Controlling creation order for test databases
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
By default, Django will always create the ``default`` database first.
|
By default, Django will always create the ``default`` database first.
|
||||||
However, no guarantees are made on the creation order of any other
|
However, no guarantees are made on the creation order of any other
|
||||||
databases in your test setup.
|
databases in your test setup.
|
||||||
|
@ -512,6 +508,13 @@ file, all Django tests run with :setting:`DEBUG`\=False. This is to ensure that
|
||||||
the observed output of your code matches what will be seen in a production
|
the observed output of your code matches what will be seen in a production
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
|
Caches are not cleared after each test, and running "manage.py test fooapp" can
|
||||||
|
insert data from the tests into the cache of a live system if you run your
|
||||||
|
tests in production because, unlike databases, a separate "test cache" is not
|
||||||
|
used. This behavior `may change`_ in the future.
|
||||||
|
|
||||||
|
.. _may change: https://code.djangoproject.com/ticket/11505
|
||||||
|
|
||||||
Understanding the test output
|
Understanding the test output
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -1001,8 +1004,6 @@ Specifically, a ``Response`` object has the following attributes:
|
||||||
The HTTP status of the response, as an integer. See
|
The HTTP status of the response, as an integer. See
|
||||||
:rfc:`2616#section-10` for a full list of HTTP status codes.
|
:rfc:`2616#section-10` for a full list of HTTP status codes.
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. attribute:: templates
|
.. attribute:: templates
|
||||||
|
|
||||||
A list of ``Template`` instances used to render the final content, in
|
A list of ``Template`` instances used to render the final content, in
|
||||||
|
@ -1089,8 +1090,6 @@ The request factory
|
||||||
|
|
||||||
.. class:: RequestFactory
|
.. class:: RequestFactory
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The :class:`~django.test.client.RequestFactory` shares the same API as
|
The :class:`~django.test.client.RequestFactory` shares the same API as
|
||||||
the test client. However, instead of behaving like a browser, the
|
the test client. However, instead of behaving like a browser, the
|
||||||
RequestFactory provides a way to generate a request instance that can
|
RequestFactory provides a way to generate a request instance that can
|
||||||
|
@ -1327,8 +1326,6 @@ This means, instead of instantiating a ``Client`` in each test::
|
||||||
Customizing the test client
|
Customizing the test client
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
.. attribute:: TestCase.client_class
|
.. attribute:: TestCase.client_class
|
||||||
|
|
||||||
If you want to use a different ``Client`` class (for example, a subclass
|
If you want to use a different ``Client`` class (for example, a subclass
|
||||||
|
@ -1708,8 +1705,6 @@ your test suite.
|
||||||
|
|
||||||
.. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True)
|
.. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Asserts that a queryset ``qs`` returns a particular list of values ``values``.
|
Asserts that a queryset ``qs`` returns a particular list of values ``values``.
|
||||||
|
|
||||||
The comparison of the contents of ``qs`` and ``values`` is performed using
|
The comparison of the contents of ``qs`` and ``values`` is performed using
|
||||||
|
@ -1730,8 +1725,6 @@ your test suite.
|
||||||
|
|
||||||
.. method:: TestCase.assertNumQueries(num, func, *args, **kwargs)
|
.. method:: TestCase.assertNumQueries(num, func, *args, **kwargs)
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that
|
||||||
``num`` database queries are executed.
|
``num`` database queries are executed.
|
||||||
|
|
||||||
|
@ -1854,8 +1847,6 @@ Skipping tests
|
||||||
|
|
||||||
.. currentmodule:: django.test
|
.. currentmodule:: django.test
|
||||||
|
|
||||||
.. versionadded:: 1.3
|
|
||||||
|
|
||||||
The unittest library provides the :func:`@skipIf <unittest.skipIf>` and
|
The unittest library provides the :func:`@skipIf <unittest.skipIf>` and
|
||||||
:func:`@skipUnless <unittest.skipUnless>` decorators to allow you to skip tests
|
:func:`@skipUnless <unittest.skipUnless>` decorators to allow you to skip tests
|
||||||
if you know ahead of time that those tests are going to fail under certain
|
if you know ahead of time that those tests are going to fail under certain
|
||||||
|
|
|
@ -52,6 +52,9 @@ class SimpleItem(models.Model):
|
||||||
class Feature(models.Model):
|
class Feature(models.Model):
|
||||||
item = models.ForeignKey(SimpleItem)
|
item = models.ForeignKey(SimpleItem)
|
||||||
|
|
||||||
|
class SpecialFeature(models.Model):
|
||||||
|
feature = models.ForeignKey(Feature)
|
||||||
|
|
||||||
class ItemAndSimpleItem(models.Model):
|
class ItemAndSimpleItem(models.Model):
|
||||||
item = models.ForeignKey(Item)
|
item = models.ForeignKey(Item)
|
||||||
simple = models.ForeignKey(SimpleItem)
|
simple = models.ForeignKey(SimpleItem)
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.db.models.loading import cache
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy,
|
from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy,
|
||||||
SimpleItem, Feature, ItemAndSimpleItem)
|
SimpleItem, Feature, ItemAndSimpleItem, SpecialFeature)
|
||||||
|
|
||||||
|
|
||||||
class DeferRegressionTest(TestCase):
|
class DeferRegressionTest(TestCase):
|
||||||
|
@ -115,6 +115,7 @@ class DeferRegressionTest(TestCase):
|
||||||
RelatedItem,
|
RelatedItem,
|
||||||
ResolveThis,
|
ResolveThis,
|
||||||
SimpleItem,
|
SimpleItem,
|
||||||
|
SpecialFeature,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -152,6 +153,7 @@ class DeferRegressionTest(TestCase):
|
||||||
"RelatedItem_Deferred_item_id",
|
"RelatedItem_Deferred_item_id",
|
||||||
"ResolveThis",
|
"ResolveThis",
|
||||||
"SimpleItem",
|
"SimpleItem",
|
||||||
|
"SpecialFeature",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -197,6 +199,18 @@ class DeferRegressionTest(TestCase):
|
||||||
self.assertEqual(obj.item, item2)
|
self.assertEqual(obj.item, item2)
|
||||||
self.assertEqual(obj.item_id, item2.id)
|
self.assertEqual(obj.item_id, item2.id)
|
||||||
|
|
||||||
|
def test_only_with_select_related(self):
|
||||||
|
# Test for #17485.
|
||||||
|
item = SimpleItem.objects.create(name='first', value=47)
|
||||||
|
feature = Feature.objects.create(item=item)
|
||||||
|
SpecialFeature.objects.create(feature=feature)
|
||||||
|
|
||||||
|
qs = Feature.objects.only('item__name').select_related('item')
|
||||||
|
self.assertEqual(len(qs), 1)
|
||||||
|
|
||||||
|
qs = SpecialFeature.objects.only('feature__item__name').select_related('feature__item')
|
||||||
|
self.assertEqual(len(qs), 1)
|
||||||
|
|
||||||
def test_deferred_class_factory(self):
|
def test_deferred_class_factory(self):
|
||||||
from django.db.models.query_utils import deferred_class_factory
|
from django.db.models.query_utils import deferred_class_factory
|
||||||
new_class = deferred_class_factory(Item,
|
new_class = deferred_class_factory(Item,
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import absolute_import, unicode_literals
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
@ -23,6 +24,7 @@ from django.core.files.uploadedfile import UploadedFile
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
|
from django.test.utils import override_settings
|
||||||
from ..servers.tests import LiveServerBase
|
from ..servers.tests import LiveServerBase
|
||||||
|
|
||||||
# Try to import PIL in either of the two ways it can end up installed.
|
# Try to import PIL in either of the two ways it can end up installed.
|
||||||
|
@ -433,22 +435,29 @@ class FileSaveRaceConditionTest(unittest.TestCase):
|
||||||
self.storage.delete('conflict')
|
self.storage.delete('conflict')
|
||||||
self.storage.delete('conflict_1')
|
self.storage.delete('conflict_1')
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.platform.startswith('win'), "Windows only partially supports umasks and chmod.")
|
||||||
class FileStoragePermissions(unittest.TestCase):
|
class FileStoragePermissions(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.old_perms = settings.FILE_UPLOAD_PERMISSIONS
|
self.umask = 0o027
|
||||||
settings.FILE_UPLOAD_PERMISSIONS = 0o666
|
self.old_umask = os.umask(self.umask)
|
||||||
self.storage_dir = tempfile.mkdtemp()
|
self.storage_dir = tempfile.mkdtemp()
|
||||||
self.storage = FileSystemStorage(self.storage_dir)
|
self.storage = FileSystemStorage(self.storage_dir)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
settings.FILE_UPLOAD_PERMISSIONS = self.old_perms
|
|
||||||
shutil.rmtree(self.storage_dir)
|
shutil.rmtree(self.storage_dir)
|
||||||
|
os.umask(self.old_umask)
|
||||||
|
|
||||||
|
@override_settings(FILE_UPLOAD_PERMISSIONS=0o654)
|
||||||
def test_file_upload_permissions(self):
|
def test_file_upload_permissions(self):
|
||||||
name = self.storage.save("the_file", ContentFile("data"))
|
name = self.storage.save("the_file", ContentFile("data"))
|
||||||
actual_mode = os.stat(self.storage.path(name))[0] & 0o777
|
actual_mode = os.stat(self.storage.path(name))[0] & 0o777
|
||||||
self.assertEqual(actual_mode, 0o666)
|
self.assertEqual(actual_mode, 0o654)
|
||||||
|
|
||||||
|
@override_settings(FILE_UPLOAD_PERMISSIONS=None)
|
||||||
|
def test_file_upload_default_permissions(self):
|
||||||
|
fname = self.storage.save("some_file", ContentFile("data"))
|
||||||
|
mode = os.stat(self.storage.path(fname))[0] & 0o777
|
||||||
|
self.assertEqual(mode, 0o666 & ~self.umask)
|
||||||
|
|
||||||
class FileStoragePathParsing(unittest.TestCase):
|
class FileStoragePathParsing(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -23,29 +23,30 @@ requires_tz_support = skipUnless(TZ_SUPPORT,
|
||||||
"time zone, but your operating system isn't able to do that.")
|
"time zone, but your operating system isn't able to do that.")
|
||||||
|
|
||||||
|
|
||||||
|
def _make_books(n, base_date):
|
||||||
|
for i in range(n):
|
||||||
|
b = Book.objects.create(
|
||||||
|
name='Book %d' % i,
|
||||||
|
slug='book-%d' % i,
|
||||||
|
pages=100+i,
|
||||||
|
pubdate=base_date - datetime.timedelta(days=i))
|
||||||
|
|
||||||
class ArchiveIndexViewTests(TestCase):
|
class ArchiveIndexViewTests(TestCase):
|
||||||
fixtures = ['generic-views-test-data.json']
|
fixtures = ['generic-views-test-data.json']
|
||||||
urls = 'regressiontests.generic_views.urls'
|
urls = 'regressiontests.generic_views.urls'
|
||||||
|
|
||||||
def _make_books(self, n, base_date):
|
|
||||||
for i in range(n):
|
|
||||||
b = Book.objects.create(
|
|
||||||
name='Book %d' % i,
|
|
||||||
slug='book-%d' % i,
|
|
||||||
pages=100+i,
|
|
||||||
pubdate=base_date - datetime.timedelta(days=1))
|
|
||||||
|
|
||||||
def test_archive_view(self):
|
def test_archive_view(self):
|
||||||
res = self.client.get('/dates/books/')
|
res = self.client.get('/dates/books/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC')))
|
||||||
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
||||||
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
||||||
|
|
||||||
def test_archive_view_context_object_name(self):
|
def test_archive_view_context_object_name(self):
|
||||||
res = self.client.get('/dates/books/context_object_name/')
|
res = self.client.get('/dates/books/context_object_name/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC')))
|
||||||
self.assertEqual(list(res.context['thingies']), list(Book.objects.all()))
|
self.assertEqual(list(res.context['thingies']), list(Book.objects.all()))
|
||||||
self.assertFalse('latest' in res.context)
|
self.assertFalse('latest' in res.context)
|
||||||
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
||||||
|
@ -65,14 +66,14 @@ class ArchiveIndexViewTests(TestCase):
|
||||||
def test_archive_view_template(self):
|
def test_archive_view_template(self):
|
||||||
res = self.client.get('/dates/books/template_name/')
|
res = self.client.get('/dates/books/template_name/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC')))
|
||||||
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
||||||
self.assertTemplateUsed(res, 'generic_views/list.html')
|
self.assertTemplateUsed(res, 'generic_views/list.html')
|
||||||
|
|
||||||
def test_archive_view_template_suffix(self):
|
def test_archive_view_template_suffix(self):
|
||||||
res = self.client.get('/dates/books/template_name_suffix/')
|
res = self.client.get('/dates/books/template_name_suffix/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC')))
|
||||||
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
self.assertEqual(list(res.context['latest']), list(Book.objects.all()))
|
||||||
self.assertTemplateUsed(res, 'generic_views/book_detail.html')
|
self.assertTemplateUsed(res, 'generic_views/book_detail.html')
|
||||||
|
|
||||||
|
@ -82,13 +83,13 @@ class ArchiveIndexViewTests(TestCase):
|
||||||
def test_archive_view_by_month(self):
|
def test_archive_view_by_month(self):
|
||||||
res = self.client.get('/dates/books/by_month/')
|
res = self.client.get('/dates/books/by_month/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'month')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'month', 'DESC')))
|
||||||
|
|
||||||
def test_paginated_archive_view(self):
|
def test_paginated_archive_view(self):
|
||||||
self._make_books(20, base_date=datetime.date.today())
|
_make_books(20, base_date=datetime.date.today())
|
||||||
res = self.client.get('/dates/books/paginated/')
|
res = self.client.get('/dates/books/paginated/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1])
|
self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC')))
|
||||||
self.assertEqual(list(res.context['latest']), list(Book.objects.all()[0:10]))
|
self.assertEqual(list(res.context['latest']), list(Book.objects.all()[0:10]))
|
||||||
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
self.assertTemplateUsed(res, 'generic_views/book_archive.html')
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ class ArchiveIndexViewTests(TestCase):
|
||||||
|
|
||||||
def test_paginated_archive_view_does_not_load_entire_table(self):
|
def test_paginated_archive_view_does_not_load_entire_table(self):
|
||||||
# Regression test for #18087
|
# Regression test for #18087
|
||||||
self._make_books(20, base_date=datetime.date.today())
|
_make_books(20, base_date=datetime.date.today())
|
||||||
# 1 query for years list + 1 query for books
|
# 1 query for years list + 1 query for books
|
||||||
with self.assertNumQueries(2):
|
with self.assertNumQueries(2):
|
||||||
self.client.get('/dates/books/')
|
self.client.get('/dates/books/')
|
||||||
|
@ -124,6 +125,13 @@ class ArchiveIndexViewTests(TestCase):
|
||||||
res = self.client.get('/dates/booksignings/')
|
res = self.client.get('/dates/booksignings/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
|
|
||||||
|
def test_date_list_order(self):
|
||||||
|
"""date_list should be sorted descending in index"""
|
||||||
|
_make_books(5, base_date=datetime.date(2011, 12, 25))
|
||||||
|
res = self.client.get('/dates/books/')
|
||||||
|
self.assertEqual(res.status_code, 200)
|
||||||
|
self.assertEqual(list(res.context['date_list']), list(reversed(sorted(res.context['date_list']))))
|
||||||
|
|
||||||
|
|
||||||
class YearArchiveViewTests(TestCase):
|
class YearArchiveViewTests(TestCase):
|
||||||
fixtures = ['generic-views-test-data.json']
|
fixtures = ['generic-views-test-data.json']
|
||||||
|
@ -202,6 +210,12 @@ class YearArchiveViewTests(TestCase):
|
||||||
res = self.client.get('/dates/booksignings/2008/')
|
res = self.client.get('/dates/booksignings/2008/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
|
|
||||||
|
def test_date_list_order(self):
|
||||||
|
"""date_list should be sorted ascending in year view"""
|
||||||
|
_make_books(10, base_date=datetime.date(2011, 12, 25))
|
||||||
|
res = self.client.get('/dates/books/2011/')
|
||||||
|
self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list'])))
|
||||||
|
|
||||||
|
|
||||||
class MonthArchiveViewTests(TestCase):
|
class MonthArchiveViewTests(TestCase):
|
||||||
fixtures = ['generic-views-test-data.json']
|
fixtures = ['generic-views-test-data.json']
|
||||||
|
@ -322,6 +336,12 @@ class MonthArchiveViewTests(TestCase):
|
||||||
res = self.client.get('/dates/booksignings/2008/apr/')
|
res = self.client.get('/dates/booksignings/2008/apr/')
|
||||||
self.assertEqual(res.status_code, 200)
|
self.assertEqual(res.status_code, 200)
|
||||||
|
|
||||||
|
def test_date_list_order(self):
|
||||||
|
"""date_list should be sorted ascending in month view"""
|
||||||
|
_make_books(10, base_date=datetime.date(2011, 12, 25))
|
||||||
|
res = self.client.get('/dates/books/2011/dec/')
|
||||||
|
self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list'])))
|
||||||
|
|
||||||
|
|
||||||
class WeekArchiveViewTests(TestCase):
|
class WeekArchiveViewTests(TestCase):
|
||||||
fixtures = ['generic-views-test-data.json']
|
fixtures = ['generic-views-test-data.json']
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import logging
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.conf import compat_patch_logging_config
|
from django.conf import compat_patch_logging_config
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.log import CallbackFilter, RequireDebugFalse, getLogger
|
from django.utils.log import CallbackFilter, RequireDebugFalse
|
||||||
|
|
||||||
|
|
||||||
# logging config prior to using filter with mail_admins
|
# logging config prior to using filter with mail_admins
|
||||||
|
@ -153,7 +154,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
token1 = 'ping'
|
token1 = 'ping'
|
||||||
token2 = 'pong'
|
token2 = 'pong'
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
admin_email_handler = self.get_admin_email_handler(logger)
|
admin_email_handler = self.get_admin_email_handler(logger)
|
||||||
# Backup then override original filters
|
# Backup then override original filters
|
||||||
orig_filters = admin_email_handler.filters
|
orig_filters = admin_email_handler.filters
|
||||||
|
@ -184,7 +185,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
token1 = 'ping'
|
token1 = 'ping'
|
||||||
token2 = 'pong'
|
token2 = 'pong'
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
admin_email_handler = self.get_admin_email_handler(logger)
|
admin_email_handler = self.get_admin_email_handler(logger)
|
||||||
# Backup then override original filters
|
# Backup then override original filters
|
||||||
orig_filters = admin_email_handler.filters
|
orig_filters = admin_email_handler.filters
|
||||||
|
@ -222,7 +223,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 0)
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
logger.error(message)
|
logger.error(message)
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
@ -247,7 +248,7 @@ class AdminEmailHandlerTest(TestCase):
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 0)
|
self.assertEqual(len(mail.outbox), 0)
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = logging.getLogger('django.request')
|
||||||
logger.error(message)
|
logger.error(message)
|
||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
|
|
@ -498,6 +498,11 @@ class LocmemBackendTests(BaseEmailBackendTests, TestCase):
|
||||||
connection2.send_messages([email])
|
connection2.send_messages([email])
|
||||||
self.assertEqual(len(mail.outbox), 2)
|
self.assertEqual(len(mail.outbox), 2)
|
||||||
|
|
||||||
|
def test_validate_multiline_headers(self):
|
||||||
|
# Ticket #18861 - Validate emails when using the locmem backend
|
||||||
|
with self.assertRaises(BadHeaderError):
|
||||||
|
send_mail('Subject\nMultiline', 'Content', 'from@example.com', ['to@example.com'])
|
||||||
|
|
||||||
|
|
||||||
class FileBackendTests(BaseEmailBackendTests, TestCase):
|
class FileBackendTests(BaseEmailBackendTests, TestCase):
|
||||||
email_backend = 'django.core.mail.backends.filebased.EmailBackend'
|
email_backend = 'django.core.mail.backends.filebased.EmailBackend'
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
def set_attr(name, value):
|
||||||
|
def wrapper(function):
|
||||||
|
setattr(function, name, value)
|
||||||
|
return function
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class Guitarist(models.Model):
|
class Guitarist(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
slug = models.CharField(max_length=50)
|
slug = models.CharField(max_length=50)
|
||||||
|
@ -9,3 +16,9 @@ class Guitarist(models.Model):
|
||||||
def url(self):
|
def url(self):
|
||||||
"Returns the URL for this guitarist."
|
"Returns the URL for this guitarist."
|
||||||
return ('guitarist_detail', [self.slug])
|
return ('guitarist_detail', [self.slug])
|
||||||
|
|
||||||
|
@models.permalink
|
||||||
|
@set_attr('attribute', 'value')
|
||||||
|
def url_with_attribute(self):
|
||||||
|
"Returns the URL for this guitarist and holds an attribute"
|
||||||
|
return ('guitarist_detail', [self.slug])
|
||||||
|
|
|
@ -16,3 +16,12 @@ class PermalinkTests(TestCase):
|
||||||
"Methods using the @permalink decorator retain their docstring."
|
"Methods using the @permalink decorator retain their docstring."
|
||||||
g = Guitarist(name='Adrien Moignard', slug='adrienmoignard')
|
g = Guitarist(name='Adrien Moignard', slug='adrienmoignard')
|
||||||
self.assertEqual(g.url.__doc__, "Returns the URL for this guitarist.")
|
self.assertEqual(g.url.__doc__, "Returns the URL for this guitarist.")
|
||||||
|
|
||||||
|
def test_wrapped_attribute(self):
|
||||||
|
"""
|
||||||
|
Methods using the @permalink decorator can have attached attributes
|
||||||
|
from other decorators
|
||||||
|
"""
|
||||||
|
g = Guitarist(name='Adrien Moignard', slug='adrienmoignard')
|
||||||
|
self.assertTrue(hasattr(g.url_with_attribute, 'attribute'))
|
||||||
|
self.assertEqual(g.url_with_attribute.attribute, 'value')
|
||||||
|
|
|
@ -16,6 +16,7 @@ from django.test import Client, TestCase
|
||||||
from django.test.client import encode_file, RequestFactory
|
from django.test.client import encode_file, RequestFactory
|
||||||
from django.test.utils import ContextList, override_settings, str_prefix
|
from django.test.utils import ContextList, override_settings, str_prefix
|
||||||
from django.template.response import SimpleTemplateResponse
|
from django.template.response import SimpleTemplateResponse
|
||||||
|
from django.utils.translation import ugettext_lazy
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,6 +130,14 @@ class AssertContainsTests(TestCase):
|
||||||
self.assertNotContains(r, 'はたけ')
|
self.assertNotContains(r, 'はたけ')
|
||||||
self.assertNotContains(r, b'\xe3\x81\xaf\xe3\x81\x9f\xe3\x81\x91'.decode('utf-8'))
|
self.assertNotContains(r, b'\xe3\x81\xaf\xe3\x81\x9f\xe3\x81\x91'.decode('utf-8'))
|
||||||
|
|
||||||
|
def test_nontext_contains(self):
|
||||||
|
r = self.client.get('/test_client_regress/no_template_view/')
|
||||||
|
self.assertContains(r, ugettext_lazy('once'))
|
||||||
|
|
||||||
|
def test_nontext_not_contains(self):
|
||||||
|
r = self.client.get('/test_client_regress/no_template_view/')
|
||||||
|
self.assertNotContains(r, ugettext_lazy('never'))
|
||||||
|
|
||||||
def test_assert_contains_renders_template_response(self):
|
def test_assert_contains_renders_template_response(self):
|
||||||
""" Test that we can pass in an unrendered SimpleTemplateReponse
|
""" Test that we can pass in an unrendered SimpleTemplateReponse
|
||||||
without throwing an error.
|
without throwing an error.
|
||||||
|
|
|
@ -72,6 +72,11 @@ class DateFormatTests(unittest.TestCase):
|
||||||
|
|
||||||
self.assertEqual(dateformat.format(my_birthday, 'a'), 'p.m.')
|
self.assertEqual(dateformat.format(my_birthday, 'a'), 'p.m.')
|
||||||
|
|
||||||
|
def test_microsecond(self):
|
||||||
|
# Regression test for #18951
|
||||||
|
dt = datetime(2009, 5, 16, microsecond=123)
|
||||||
|
self.assertEqual(dateformat.format(dt, 'u'), '000123')
|
||||||
|
|
||||||
def test_date_formats(self):
|
def test_date_formats(self):
|
||||||
my_birthday = datetime(1979, 7, 8, 22, 00)
|
my_birthday = datetime(1979, 7, 8, 22, 00)
|
||||||
timestamp = datetime(2008, 5, 19, 11, 45, 23, 123456)
|
timestamp = datetime(2008, 5, 19, 11, 45, 23, 123456)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
from unittest import TestCase
|
||||||
|
from django.utils.numberformat import format as nformat
|
||||||
|
from sys import float_info
|
||||||
|
|
||||||
|
|
||||||
|
class TestNumberFormat(TestCase):
|
||||||
|
|
||||||
|
def test_format_number(self):
|
||||||
|
self.assertEqual(nformat(1234, '.'), '1234')
|
||||||
|
self.assertEqual(nformat(1234.2, '.'), '1234.2')
|
||||||
|
self.assertEqual(nformat(1234, '.', decimal_pos=2), '1234.00')
|
||||||
|
self.assertEqual(nformat(1234, '.', grouping=2, thousand_sep=','),
|
||||||
|
'1234')
|
||||||
|
self.assertEqual(nformat(1234, '.', grouping=2, thousand_sep=',',
|
||||||
|
force_grouping=True), '12,34')
|
||||||
|
self.assertEqual(nformat(-1234.33, '.', decimal_pos=1), '-1234.3')
|
||||||
|
|
||||||
|
def test_format_string(self):
|
||||||
|
self.assertEqual(nformat('1234', '.'), '1234')
|
||||||
|
self.assertEqual(nformat('1234.2', '.'), '1234.2')
|
||||||
|
self.assertEqual(nformat('1234', '.', decimal_pos=2), '1234.00')
|
||||||
|
self.assertEqual(nformat('1234', '.', grouping=2, thousand_sep=','),
|
||||||
|
'1234')
|
||||||
|
self.assertEqual(nformat('1234', '.', grouping=2, thousand_sep=',',
|
||||||
|
force_grouping=True), '12,34')
|
||||||
|
self.assertEqual(nformat('-1234.33', '.', decimal_pos=1), '-1234.3')
|
||||||
|
|
||||||
|
def test_large_number(self):
|
||||||
|
most_max = ('{0}179769313486231570814527423731704356798070567525844996'
|
||||||
|
'598917476803157260780028538760589558632766878171540458953'
|
||||||
|
'514382464234321326889464182768467546703537516986049910576'
|
||||||
|
'551282076245490090389328944075868508455133942304583236903'
|
||||||
|
'222948165808559332123348274797826204144723168738177180919'
|
||||||
|
'29988125040402618412485836{1}')
|
||||||
|
most_max2 = ('{0}35953862697246314162905484746340871359614113505168999'
|
||||||
|
'31978349536063145215600570775211791172655337563430809179'
|
||||||
|
'07028764928468642653778928365536935093407075033972099821'
|
||||||
|
'15310256415249098018077865788815173701691026788460916647'
|
||||||
|
'38064458963316171186642466965495956524082894463374763543'
|
||||||
|
'61838599762500808052368249716736')
|
||||||
|
int_max = int(float_info.max)
|
||||||
|
self.assertEqual(nformat(int_max, '.'), most_max.format('', '8'))
|
||||||
|
self.assertEqual(nformat(int_max + 1, '.'), most_max.format('', '9'))
|
||||||
|
self.assertEqual(nformat(int_max * 2, '.'), most_max2.format(''))
|
||||||
|
self.assertEqual(nformat(0 - int_max, '.'), most_max.format('-', '8'))
|
||||||
|
self.assertEqual(nformat(-1 - int_max, '.'), most_max.format('-', '9'))
|
||||||
|
self.assertEqual(nformat(-2 * int_max, '.'), most_max2.format('-'))
|
|
@ -21,6 +21,7 @@ from .http import TestUtilsHttp
|
||||||
from .ipv6 import TestUtilsIPv6
|
from .ipv6 import TestUtilsIPv6
|
||||||
from .jslex import JsToCForGettextTest, JsTokensTest
|
from .jslex import JsToCForGettextTest, JsTokensTest
|
||||||
from .module_loading import CustomLoader, DefaultLoader, EggLoader
|
from .module_loading import CustomLoader, DefaultLoader, EggLoader
|
||||||
|
from .numberformat import TestNumberFormat
|
||||||
from .os_utils import SafeJoinTests
|
from .os_utils import SafeJoinTests
|
||||||
from .regex_helper import NormalizeTests
|
from .regex_helper import NormalizeTests
|
||||||
from .simplelazyobject import TestUtilsSimpleLazyObject
|
from .simplelazyobject import TestUtilsSimpleLazyObject
|
||||||
|
|
Loading…
Reference in New Issue