Merged master changes.
This commit is contained in:
commit
7e82e83d67
|
@ -1,4 +1,4 @@
|
||||||
include README
|
include README.rst
|
||||||
include AUTHORS
|
include AUTHORS
|
||||||
include INSTALL
|
include INSTALL
|
||||||
include LICENSE
|
include LICENSE
|
||||||
|
|
|
@ -152,17 +152,25 @@ class UserSettingsHolder(BaseSettings):
|
||||||
Requests for configuration variables not in this class are satisfied
|
Requests for configuration variables not in this class are satisfied
|
||||||
from the module specified in default_settings (if possible).
|
from the module specified in default_settings (if possible).
|
||||||
"""
|
"""
|
||||||
|
self.__dict__['_deleted'] = set()
|
||||||
self.default_settings = default_settings
|
self.default_settings = default_settings
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
|
if name in self._deleted:
|
||||||
|
raise AttributeError
|
||||||
return getattr(self.default_settings, name)
|
return getattr(self.default_settings, name)
|
||||||
|
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
self._deleted.discard(name)
|
||||||
|
return super(UserSettingsHolder, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
def __delattr__(self, name):
|
||||||
|
self._deleted.add(name)
|
||||||
|
return super(UserSettingsHolder, self).__delattr__(name)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return list(self.__dict__) + dir(self.default_settings)
|
return list(self.__dict__) + dir(self.default_settings)
|
||||||
|
|
||||||
# For Python < 2.6:
|
|
||||||
__members__ = property(lambda self: self.__dir__())
|
|
||||||
|
|
||||||
settings = LazySettings()
|
settings = LazySettings()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,11 @@ DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
|
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
|
||||||
'NAME': '', # Or path to database file if using sqlite3.
|
'NAME': '', # Or path to database file if using sqlite3.
|
||||||
'USER': '', # Not used with sqlite3.
|
# The following settings are not used with sqlite3:
|
||||||
'PASSWORD': '', # Not used with sqlite3.
|
'USER': '',
|
||||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
'PASSWORD': '',
|
||||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
|
||||||
|
'PORT': '', # Set to empty string for default.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
{% if change %}{% if not is_popup %}
|
{% if change %}{% if not is_popup %}
|
||||||
<ul class="object-tools">
|
<ul class="object-tools">
|
||||||
{% block object-tools-items %}
|
{% block object-tools-items %}
|
||||||
<li><a href="history/" class="historylink">{% trans "History" %}</a></li>
|
<li><a href="{% url opts|admin_urlname:'history' original.pk %}" class="historylink">{% trans "History" %}</a></li>
|
||||||
{% if has_absolute_url %}<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
|
{% if has_absolute_url %}<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.utils import formats
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import force_text, smart_text, smart_bytes
|
from django.utils.encoding import force_str, force_text, smart_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.translation import ungettext
|
from django.utils.translation import ungettext
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
@ -277,7 +277,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
|
||||||
label = force_text(model._meta.verbose_name)
|
label = force_text(model._meta.verbose_name)
|
||||||
attr = six.text_type
|
attr = six.text_type
|
||||||
elif name == "__str__":
|
elif name == "__str__":
|
||||||
label = smart_bytes(model._meta.verbose_name)
|
label = force_str(model._meta.verbose_name)
|
||||||
attr = bytes
|
attr = bytes
|
||||||
else:
|
else:
|
||||||
if callable(name):
|
if callable(name):
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.core.paginator import InvalidPage
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
from django.db.models.fields import FieldDoesNotExist
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.encoding import force_text, smart_bytes
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.translation import ugettext, ugettext_lazy
|
from django.utils.translation import ugettext, ugettext_lazy
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ class ChangeList(object):
|
||||||
# 'key' will be used as a keyword argument later, so Python
|
# 'key' will be used as a keyword argument later, so Python
|
||||||
# requires it to be a string.
|
# requires it to be a string.
|
||||||
del lookup_params[key]
|
del lookup_params[key]
|
||||||
lookup_params[smart_bytes(key)] = value
|
lookup_params[force_str(key)] = value
|
||||||
|
|
||||||
if not self.model_admin.lookup_allowed(key, value):
|
if not self.model_admin.lookup_allowed(key, value):
|
||||||
raise SuspiciousOperation("Filtering by %s not allowed" % key)
|
raise SuspiciousOperation("Filtering by %s not allowed" % key)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from email.errors import HeaderParseError
|
||||||
|
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
try:
|
try:
|
||||||
import docutils.core
|
import docutils.core
|
||||||
import docutils.nodes
|
import docutils.nodes
|
||||||
|
@ -66,7 +66,7 @@ def parse_rst(text, default_reference_context, thing_being_parsed=None):
|
||||||
"link_base" : reverse('django-admindocs-docroot').rstrip('/')
|
"link_base" : reverse('django-admindocs-docroot').rstrip('/')
|
||||||
}
|
}
|
||||||
if thing_being_parsed:
|
if thing_being_parsed:
|
||||||
thing_being_parsed = smart_bytes("<%s>" % thing_being_parsed)
|
thing_being_parsed = force_bytes("<%s>" % thing_being_parsed)
|
||||||
parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
|
parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
|
||||||
destination_path=None, writer_name='html',
|
destination_path=None, writer_name='html',
|
||||||
settings_overrides=overrides)
|
settings_overrides=overrides)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.conf import settings
|
||||||
from django.test.signals import setting_changed
|
from django.test.signals import setting_changed
|
||||||
from django.utils import importlib
|
from django.utils import importlib
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.crypto import (
|
from django.utils.crypto import (
|
||||||
pbkdf2, constant_time_compare, get_random_string)
|
pbkdf2, constant_time_compare, get_random_string)
|
||||||
|
@ -299,7 +299,7 @@ class SHA1PasswordHasher(BasePasswordHasher):
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
assert password
|
assert password
|
||||||
assert salt and '$' not in salt
|
assert salt and '$' not in salt
|
||||||
hash = hashlib.sha1(smart_bytes(salt + password)).hexdigest()
|
hash = hashlib.sha1(force_bytes(salt + password)).hexdigest()
|
||||||
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
||||||
|
|
||||||
def verify(self, password, encoded):
|
def verify(self, password, encoded):
|
||||||
|
@ -327,7 +327,7 @@ class MD5PasswordHasher(BasePasswordHasher):
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
assert password
|
assert password
|
||||||
assert salt and '$' not in salt
|
assert salt and '$' not in salt
|
||||||
hash = hashlib.md5(smart_bytes(salt + password)).hexdigest()
|
hash = hashlib.md5(force_bytes(salt + password)).hexdigest()
|
||||||
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
||||||
|
|
||||||
def verify(self, password, encoded):
|
def verify(self, password, encoded):
|
||||||
|
@ -361,7 +361,7 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
return hashlib.md5(smart_bytes(password)).hexdigest()
|
return hashlib.md5(force_bytes(password)).hexdigest()
|
||||||
|
|
||||||
def verify(self, password, encoded):
|
def verify(self, password, encoded):
|
||||||
encoded_2 = self.encode(password, '')
|
encoded_2 = self.encode(password, '')
|
||||||
|
|
|
@ -10,6 +10,7 @@ import unicodedata
|
||||||
from django.contrib.auth import models as auth_app, get_user_model
|
from django.contrib.auth import models as auth_app, get_user_model
|
||||||
from django.core import exceptions
|
from django.core import exceptions
|
||||||
from django.db.models import get_models, signals
|
from django.db.models import get_models, signals
|
||||||
|
from django.utils import six
|
||||||
from django.utils.six.moves import input
|
from django.utils.six.moves import input
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,17 +88,23 @@ def get_system_username():
|
||||||
:returns: The username as a unicode string, or an empty string if the
|
:returns: The username as a unicode string, or an empty string if the
|
||||||
username could not be determined.
|
username could not be determined.
|
||||||
"""
|
"""
|
||||||
default_locale = locale.getdefaultlocale()[1]
|
try:
|
||||||
if default_locale:
|
result = getpass.getuser()
|
||||||
|
except (ImportError, KeyError):
|
||||||
|
# KeyError will be raised by os.getpwuid() (called by getuser())
|
||||||
|
# if there is no corresponding entry in the /etc/passwd file
|
||||||
|
# (a very restricted chroot environment, for example).
|
||||||
|
return ''
|
||||||
|
if not six.PY3:
|
||||||
|
default_locale = locale.getdefaultlocale()[1]
|
||||||
|
if not default_locale:
|
||||||
|
return ''
|
||||||
try:
|
try:
|
||||||
return getpass.getuser().decode(default_locale)
|
result = result.decode(default_locale)
|
||||||
except (ImportError, KeyError, UnicodeDecodeError):
|
except UnicodeDecodeError:
|
||||||
# KeyError will be raised by os.getpwuid() (called by getuser())
|
|
||||||
# if there is no corresponding entry in the /etc/passwd file
|
|
||||||
# (a very restricted chroot environment, for example).
|
|
||||||
# UnicodeDecodeError - preventive treatment for non-latin Windows.
|
# UnicodeDecodeError - preventive treatment for non-latin Windows.
|
||||||
pass
|
return ''
|
||||||
return ''
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_default_username(check_db=True):
|
def get_default_username(check_db=True):
|
||||||
|
|
|
@ -9,16 +9,20 @@ from django.core.management import call_command
|
||||||
from django.core.management.base import CommandError
|
from django.core.management.base import CommandError
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
from django.utils import six
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
|
|
||||||
class GetDefaultUsernameTestCase(TestCase):
|
class GetDefaultUsernameTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self._getpass_getuser = management.get_system_username
|
self.old_get_system_username = management.get_system_username
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
management.get_system_username = self._getpass_getuser
|
management.get_system_username = self.old_get_system_username
|
||||||
|
|
||||||
|
def test_actual_implementation(self):
|
||||||
|
self.assertIsInstance(management.get_system_username(), six.text_type)
|
||||||
|
|
||||||
def test_simple(self):
|
def test_simple(self):
|
||||||
management.get_system_username = lambda: 'joe'
|
management.get_system_username = lambda: 'joe'
|
||||||
|
|
|
@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.encoding import smart_text, smart_str, iri_to_uri
|
from django.utils.encoding import smart_text, force_str, iri_to_uri
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class EasyModel(object):
|
||||||
self.verbose_name_plural = model._meta.verbose_name_plural
|
self.verbose_name_plural = model._meta.verbose_name_plural
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyModel for %s>' % self.model._meta.object_name)
|
return force_str('<EasyModel for %s>' % self.model._meta.object_name)
|
||||||
|
|
||||||
def model_databrowse(self):
|
def model_databrowse(self):
|
||||||
"Returns the ModelDatabrowse class for this model."
|
"Returns the ModelDatabrowse class for this model."
|
||||||
|
@ -62,7 +62,7 @@ class EasyField(object):
|
||||||
self.model, self.field = easy_model, field
|
self.model, self.field = easy_model, field
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return force_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
||||||
|
|
||||||
def choices(self):
|
def choices(self):
|
||||||
for value, label in self.field.choices:
|
for value, label in self.field.choices:
|
||||||
|
@ -80,7 +80,7 @@ class EasyChoice(object):
|
||||||
self.value, self.label = value, label
|
self.value, self.label = value, label
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return force_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
||||||
|
|
||||||
def url(self):
|
def url(self):
|
||||||
return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
|
return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
|
||||||
|
@ -91,7 +91,7 @@ class EasyInstance(object):
|
||||||
self.model, self.instance = easy_model, instance
|
self.model, self.instance = easy_model, instance
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
|
return force_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
val = smart_text(self.instance)
|
val = smart_text(self.instance)
|
||||||
|
@ -135,7 +135,7 @@ class EasyInstanceField(object):
|
||||||
self.raw_value = getattr(instance.instance, field.name)
|
self.raw_value = getattr(instance.instance, field.name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return force_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
from django.db.models.query import QuerySet, ValuesQuerySet, ValuesListQuerySet
|
from django.db.models.query import QuerySet, ValuesQuerySet, ValuesListQuerySet
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
from django.contrib.gis.db.models import aggregates
|
from django.contrib.gis.db.models import aggregates
|
||||||
from django.contrib.gis.db.models.fields import get_srid_info, PointField, LineStringField
|
from django.contrib.gis.db.models.fields import get_srid_info, PointField, LineStringField
|
||||||
from django.contrib.gis.db.models.sql import AreaField, DistanceField, GeomField, GeoQuery
|
from django.contrib.gis.db.models.sql import AreaField, DistanceField, GeomField, GeoQuery
|
||||||
from django.contrib.gis.geometry.backend import Geometry
|
from django.contrib.gis.geometry.backend import Geometry
|
||||||
from django.contrib.gis.measure import Area, Distance
|
from django.contrib.gis.measure import Area, Distance
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
class GeoQuerySet(QuerySet):
|
class GeoQuerySet(QuerySet):
|
||||||
"The Geographic QuerySet."
|
"The Geographic QuerySet."
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
from django.contrib.gis.db.models.fields import GeometryField
|
from django.contrib.gis.db.models.fields import GeometryField
|
||||||
from django.db import connections, DEFAULT_DB_ALIAS
|
from django.db import connections, DEFAULT_DB_ALIAS
|
||||||
from django.db.models import get_model
|
from django.db.models import get_model
|
||||||
from django.utils.encoding import smart_bytes
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ def sitemap(request, sitemaps, section=None):
|
||||||
raise Http404(_("Page %s empty") % page)
|
raise Http404(_("Page %s empty") % page)
|
||||||
except PageNotAnInteger:
|
except PageNotAnInteger:
|
||||||
raise Http404(_("No page '%s'") % page)
|
raise Http404(_("No page '%s'") % page)
|
||||||
xml = smart_bytes(loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls}))
|
xml = loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls})
|
||||||
return HttpResponse(xml, content_type='application/xml')
|
return HttpResponse(xml, content_type='application/xml')
|
||||||
|
|
||||||
def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS):
|
def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS):
|
||||||
|
|
|
@ -186,6 +186,15 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(1, qs.count())
|
self.assertEqual(1, qs.count())
|
||||||
for pc in qs: self.assertEqual(32128, pc.point.srid)
|
for pc in qs: self.assertEqual(32128, pc.point.srid)
|
||||||
|
|
||||||
|
def test_raw_sql_query(self):
|
||||||
|
"Testing raw SQL query."
|
||||||
|
cities1 = City.objects.all()
|
||||||
|
# Only PostGIS would support a 'select *' query because of its recognized
|
||||||
|
# HEXEWKB format for geometry fields
|
||||||
|
cities2 = City.objects.raw('select id, name, asText(point) from geoapp_city')
|
||||||
|
self.assertEqual(len(cities1), len(list(cities2)))
|
||||||
|
self.assertTrue(isinstance(cities2[0].point, Point))
|
||||||
|
|
||||||
|
|
||||||
class GeoLookupTest(TestCase):
|
class GeoLookupTest(TestCase):
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ markup syntaxes to HTML; currently there is support for:
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
@ -27,7 +27,7 @@ def textile(value):
|
||||||
raise template.TemplateSyntaxError("Error in 'textile' filter: The Python textile library isn't installed.")
|
raise template.TemplateSyntaxError("Error in 'textile' filter: The Python textile library isn't installed.")
|
||||||
return force_text(value)
|
return force_text(value)
|
||||||
else:
|
else:
|
||||||
return mark_safe(force_text(textile.textile(smart_bytes(value), encoding='utf-8', output='utf-8')))
|
return mark_safe(force_text(textile.textile(force_bytes(value), encoding='utf-8', output='utf-8')))
|
||||||
|
|
||||||
@register.filter(is_safe=True)
|
@register.filter(is_safe=True)
|
||||||
def markdown(value, arg=''):
|
def markdown(value, arg=''):
|
||||||
|
@ -80,5 +80,5 @@ def restructuredtext(value):
|
||||||
return force_text(value)
|
return force_text(value)
|
||||||
else:
|
else:
|
||||||
docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
|
docutils_settings = getattr(settings, "RESTRUCTUREDTEXT_FILTER_SETTINGS", {})
|
||||||
parts = publish_parts(source=smart_bytes(value), writer_name="html4css1", settings_overrides=docutils_settings)
|
parts = publish_parts(source=force_bytes(value), writer_name="html4css1", settings_overrides=docutils_settings)
|
||||||
return mark_safe(force_text(parts["fragment"]))
|
return mark_safe(force_text(parts["fragment"]))
|
||||||
|
|
|
@ -14,7 +14,7 @@ from django.utils.crypto import constant_time_compare
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from django.utils.crypto import salted_hmac
|
from django.utils.crypto import salted_hmac
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
class CreateError(Exception):
|
class CreateError(Exception):
|
||||||
"""
|
"""
|
||||||
|
@ -84,7 +84,7 @@ class SessionBase(object):
|
||||||
return base64.b64encode(hash.encode() + b":" + pickled).decode('ascii')
|
return base64.b64encode(hash.encode() + b":" + pickled).decode('ascii')
|
||||||
|
|
||||||
def decode(self, session_data):
|
def decode(self, session_data):
|
||||||
encoded_data = base64.b64decode(smart_bytes(session_data))
|
encoded_data = base64.b64decode(force_bytes(session_data))
|
||||||
try:
|
try:
|
||||||
# could produce ValueError if there is no ':'
|
# could produce ValueError if there is no ':'
|
||||||
hash, pickled = encoded_data.split(b':', 1)
|
hash, pickled = encoded_data.split(b':', 1)
|
||||||
|
|
|
@ -192,7 +192,7 @@ Type 'yes' to continue, or 'no' to cancel: """
|
||||||
|
|
||||||
def clear_dir(self, path):
|
def clear_dir(self, path):
|
||||||
"""
|
"""
|
||||||
Deletes the given relative path using the destinatin storage backend.
|
Deletes the given relative path using the destination storage backend.
|
||||||
"""
|
"""
|
||||||
dirs, files = self.storage.listdir(path)
|
dirs, files = self.storage.listdir(path)
|
||||||
for f in files:
|
for f in files:
|
||||||
|
|
|
@ -16,7 +16,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.files.storage import FileSystemStorage, get_storage_class
|
from django.core.files.storage import FileSystemStorage, get_storage_class
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.encoding import force_text, smart_bytes
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.functional import LazyObject
|
from django.utils.functional import LazyObject
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class CachedFilesMixin(object):
|
||||||
return urlunsplit(unparsed_name)
|
return urlunsplit(unparsed_name)
|
||||||
|
|
||||||
def cache_key(self, name):
|
def cache_key(self, name):
|
||||||
return 'staticfiles:%s' % hashlib.md5(smart_bytes(name)).hexdigest()
|
return 'staticfiles:%s' % hashlib.md5(force_bytes(name)).hexdigest()
|
||||||
|
|
||||||
def url(self, name, force=False):
|
def url(self, name, force=False):
|
||||||
"""
|
"""
|
||||||
|
@ -254,7 +254,7 @@ class CachedFilesMixin(object):
|
||||||
if hashed_file_exists:
|
if hashed_file_exists:
|
||||||
self.delete(hashed_name)
|
self.delete(hashed_name)
|
||||||
# then save the processed result
|
# then save the processed result
|
||||||
content_file = ContentFile(smart_bytes(content))
|
content_file = ContentFile(force_bytes(content))
|
||||||
saved_name = self._save(hashed_name, content_file)
|
saved_name = self._save(hashed_name, content_file)
|
||||||
hashed_name = force_text(saved_name.replace('\\', '/'))
|
hashed_name = force_text(saved_name.replace('\\', '/'))
|
||||||
processed = True
|
processed = True
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.conf import settings
|
||||||
from django.core.cache.backends.base import BaseCache
|
from django.core.cache.backends.base import BaseCache
|
||||||
from django.db import connections, router, transaction, DatabaseError
|
from django.db import connections, router, transaction, DatabaseError
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
|
|
||||||
class Options(object):
|
class Options(object):
|
||||||
|
@ -73,7 +73,7 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
transaction.commit_unless_managed(using=db)
|
transaction.commit_unless_managed(using=db)
|
||||||
return default
|
return default
|
||||||
value = connections[db].ops.process_clob(row[1])
|
value = connections[db].ops.process_clob(row[1])
|
||||||
return pickle.loads(base64.b64decode(smart_bytes(value)))
|
return pickle.loads(base64.b64decode(force_bytes(value)))
|
||||||
|
|
||||||
def set(self, key, value, timeout=None, version=None):
|
def set(self, key, value, timeout=None, version=None):
|
||||||
key = self.make_key(key, version=version)
|
key = self.make_key(key, version=version)
|
||||||
|
|
|
@ -10,7 +10,7 @@ except ImportError:
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
from django.core.cache.backends.base import BaseCache
|
from django.core.cache.backends.base import BaseCache
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
|
||||||
class FileBasedCache(BaseCache):
|
class FileBasedCache(BaseCache):
|
||||||
def __init__(self, dir, params):
|
def __init__(self, dir, params):
|
||||||
|
@ -137,7 +137,7 @@ class FileBasedCache(BaseCache):
|
||||||
Thus, a cache key of "foo" gets turnned into a file named
|
Thus, a cache key of "foo" gets turnned into a file named
|
||||||
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
|
``{cache-dir}ac/bd/18db4cc2f85cedef654fccc4a4d8``.
|
||||||
"""
|
"""
|
||||||
path = hashlib.md5(smart_bytes(key)).hexdigest()
|
path = hashlib.md5(force_bytes(key)).hexdigest()
|
||||||
path = os.path.join(path[:2], path[2:4], path[4:])
|
path = os.path.join(path[:2], path[2:4], path[4:])
|
||||||
return os.path.join(self._dir, path)
|
return os.path.join(self._dir, path)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from threading import local
|
||||||
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
||||||
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
class BaseMemcachedCache(BaseCache):
|
class BaseMemcachedCache(BaseCache):
|
||||||
def __init__(self, server, params, library, value_not_found_exception):
|
def __init__(self, server, params, library, value_not_found_exception):
|
||||||
|
@ -53,7 +53,7 @@ class BaseMemcachedCache(BaseCache):
|
||||||
|
|
||||||
def make_key(self, key, version=None):
|
def make_key(self, key, version=None):
|
||||||
# Python 2 memcache requires the key to be a byte string.
|
# Python 2 memcache requires the key to be a byte string.
|
||||||
return smart_str(super(BaseMemcachedCache, self).make_key(key, version))
|
return force_str(super(BaseMemcachedCache, self).make_key(key, version))
|
||||||
|
|
||||||
def add(self, key, value, timeout=0, version=None):
|
def add(self, key, value, timeout=0, version=None):
|
||||||
key = self.make_key(key, version=version)
|
key = self.make_key(key, version=version)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from io import BytesIO, UnsupportedOperation
|
from io import BytesIO, StringIO, UnsupportedOperation
|
||||||
|
|
||||||
from django.utils.encoding import smart_bytes, smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.core.files.utils import FileProxyMixin
|
from django.core.files.utils import FileProxyMixin
|
||||||
|
from django.utils import six
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
|
@ -132,7 +133,8 @@ class ContentFile(File):
|
||||||
"""
|
"""
|
||||||
def __init__(self, content, name=None):
|
def __init__(self, content, name=None):
|
||||||
content = content or b''
|
content = content or b''
|
||||||
super(ContentFile, self).__init__(BytesIO(content), name=name)
|
stream_class = StringIO if isinstance(content, six.text_type) else BytesIO
|
||||||
|
super(ContentFile, self).__init__(stream_class(content), name=name)
|
||||||
self.size = len(content)
|
self.size = len(content)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -195,11 +195,18 @@ class FileSystemStorage(Storage):
|
||||||
fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
|
fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
|
||||||
try:
|
try:
|
||||||
locks.lock(fd, locks.LOCK_EX)
|
locks.lock(fd, locks.LOCK_EX)
|
||||||
|
_file = None
|
||||||
for chunk in content.chunks():
|
for chunk in content.chunks():
|
||||||
os.write(fd, chunk)
|
if _file is None:
|
||||||
|
mode = 'wb' if isinstance(chunk, bytes) else 'wt'
|
||||||
|
_file = os.fdopen(fd, mode)
|
||||||
|
_file.write(chunk)
|
||||||
finally:
|
finally:
|
||||||
locks.unlock(fd)
|
locks.unlock(fd)
|
||||||
os.close(fd)
|
if _file is not None:
|
||||||
|
_file.close()
|
||||||
|
else:
|
||||||
|
os.close(fd)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.EEXIST:
|
if e.errno == errno.EEXIST:
|
||||||
# Ooops, the file exists. We need a new file name.
|
# Ooops, the file exists. We need a new file name.
|
||||||
|
|
|
@ -8,7 +8,7 @@ from io import BytesIO
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.base import File
|
from django.core.files.base import File
|
||||||
from django.core.files import temp as tempfile
|
from django.core.files import temp as tempfile
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
|
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
|
||||||
'SimpleUploadedFile')
|
'SimpleUploadedFile')
|
||||||
|
@ -30,7 +30,7 @@ class UploadedFile(File):
|
||||||
self.charset = charset
|
self.charset = charset
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str("<%s: %s (%s)>" % (
|
return force_str("<%s: %s (%s)>" % (
|
||||||
self.__class__.__name__, self.name, self.content_type))
|
self.__class__.__name__, self.name, self.content_type))
|
||||||
|
|
||||||
def _get_name(self):
|
def _get_name(self):
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.core import signals
|
||||||
from django.core.handlers import base
|
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_text, smart_str, iri_to_uri
|
from django.utils.encoding import force_str, force_text, iri_to_uri
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = getLogger('django.request')
|
||||||
|
@ -246,5 +246,5 @@ class WSGIHandler(base.BaseHandler):
|
||||||
response_headers = [(str(k), str(v)) for k, v in response.items()]
|
response_headers = [(str(k), str(v)) for k, v in response.items()]
|
||||||
for c in response.cookies.values():
|
for c in response.cookies.values():
|
||||||
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
|
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
|
||||||
start_response(smart_str(status), response_headers)
|
start_response(force_str(status), response_headers)
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -12,7 +12,7 @@ import traceback
|
||||||
import django
|
import django
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.management.color import color_style
|
from django.core.management.color import color_style
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class OutputWrapper(object):
|
||||||
msg += ending
|
msg += ending
|
||||||
style_func = [f for f in (style_func, self.style_func, lambda x:x)
|
style_func = [f for f in (style_func, self.style_func, lambda x:x)
|
||||||
if f is not None][0]
|
if f is not None][0]
|
||||||
self._out.write(smart_str(style_func(msg)))
|
self._out.write(force_str(style_func(msg)))
|
||||||
|
|
||||||
|
|
||||||
class BaseCommand(object):
|
class BaseCommand(object):
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import keyword
|
import keyword
|
||||||
|
import re
|
||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
|
|
||||||
from django.core.management.base import NoArgsCommand, CommandError
|
from django.core.management.base import NoArgsCommand, CommandError
|
||||||
|
@ -31,6 +34,7 @@ class Command(NoArgsCommand):
|
||||||
table_name_filter = options.get('table_name_filter')
|
table_name_filter = options.get('table_name_filter')
|
||||||
|
|
||||||
table2model = lambda table_name: table_name.title().replace('_', '').replace(' ', '').replace('-', '')
|
table2model = lambda table_name: table_name.title().replace('_', '').replace(' ', '').replace('-', '')
|
||||||
|
strip_prefix = lambda s: s.startswith("u'") and s[1:] or s
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
yield "# This is an auto-generated Django model module."
|
yield "# This is an auto-generated Django model module."
|
||||||
|
@ -41,6 +45,7 @@ class Command(NoArgsCommand):
|
||||||
yield "#"
|
yield "#"
|
||||||
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
|
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
|
||||||
yield "# into your database."
|
yield "# into your database."
|
||||||
|
yield "from __future__ import unicode_literals"
|
||||||
yield ''
|
yield ''
|
||||||
yield 'from %s import models' % self.db_module
|
yield 'from %s import models' % self.db_module
|
||||||
yield ''
|
yield ''
|
||||||
|
@ -59,16 +64,19 @@ class Command(NoArgsCommand):
|
||||||
indexes = connection.introspection.get_indexes(cursor, table_name)
|
indexes = connection.introspection.get_indexes(cursor, table_name)
|
||||||
except NotImplementedError:
|
except NotImplementedError:
|
||||||
indexes = {}
|
indexes = {}
|
||||||
|
used_column_names = [] # Holds column names used in the table so far
|
||||||
for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
|
for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
|
||||||
column_name = row[0]
|
|
||||||
att_name = column_name.lower()
|
|
||||||
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
||||||
extra_params = {} # Holds Field parameters such as 'db_column'.
|
extra_params = {} # Holds Field parameters such as 'db_column'.
|
||||||
|
column_name = row[0]
|
||||||
|
is_relation = i in relations
|
||||||
|
|
||||||
# If the column name can't be used verbatim as a Python
|
att_name, params, notes = self.normalize_col_name(
|
||||||
# attribute, set the "db_column" for this Field.
|
column_name, used_column_names, is_relation)
|
||||||
if ' ' in att_name or '-' in att_name or keyword.iskeyword(att_name) or column_name != att_name:
|
extra_params.update(params)
|
||||||
extra_params['db_column'] = column_name
|
comment_notes.extend(notes)
|
||||||
|
|
||||||
|
used_column_names.append(att_name)
|
||||||
|
|
||||||
# Add primary_key and unique, if necessary.
|
# Add primary_key and unique, if necessary.
|
||||||
if column_name in indexes:
|
if column_name in indexes:
|
||||||
|
@ -77,30 +85,12 @@ class Command(NoArgsCommand):
|
||||||
elif indexes[column_name]['unique']:
|
elif indexes[column_name]['unique']:
|
||||||
extra_params['unique'] = True
|
extra_params['unique'] = True
|
||||||
|
|
||||||
# Modify the field name to make it Python-compatible.
|
if is_relation:
|
||||||
if ' ' in att_name:
|
|
||||||
att_name = att_name.replace(' ', '_')
|
|
||||||
comment_notes.append('Field renamed to remove spaces.')
|
|
||||||
|
|
||||||
if '-' in att_name:
|
|
||||||
att_name = att_name.replace('-', '_')
|
|
||||||
comment_notes.append('Field renamed to remove dashes.')
|
|
||||||
|
|
||||||
if column_name != att_name:
|
|
||||||
comment_notes.append('Field name made lowercase.')
|
|
||||||
|
|
||||||
if i in relations:
|
|
||||||
rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
|
rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
|
||||||
|
|
||||||
if rel_to in known_models:
|
if rel_to in known_models:
|
||||||
field_type = 'ForeignKey(%s' % rel_to
|
field_type = 'ForeignKey(%s' % rel_to
|
||||||
else:
|
else:
|
||||||
field_type = "ForeignKey('%s'" % rel_to
|
field_type = "ForeignKey('%s'" % rel_to
|
||||||
|
|
||||||
if att_name.endswith('_id'):
|
|
||||||
att_name = att_name[:-3]
|
|
||||||
else:
|
|
||||||
extra_params['db_column'] = column_name
|
|
||||||
else:
|
else:
|
||||||
# Calling `get_field_type` to get the field type string and any
|
# Calling `get_field_type` to get the field type string and any
|
||||||
# additional paramters and notes.
|
# additional paramters and notes.
|
||||||
|
@ -110,16 +100,6 @@ class Command(NoArgsCommand):
|
||||||
|
|
||||||
field_type += '('
|
field_type += '('
|
||||||
|
|
||||||
if keyword.iskeyword(att_name):
|
|
||||||
att_name += '_field'
|
|
||||||
comment_notes.append('Field renamed because it was a Python reserved word.')
|
|
||||||
|
|
||||||
if att_name[0].isdigit():
|
|
||||||
att_name = 'number_%s' % att_name
|
|
||||||
extra_params['db_column'] = six.text_type(column_name)
|
|
||||||
comment_notes.append("Field renamed because it wasn't a "
|
|
||||||
"valid Python identifier.")
|
|
||||||
|
|
||||||
# Don't output 'id = meta.AutoField(primary_key=True)', because
|
# Don't output 'id = meta.AutoField(primary_key=True)', because
|
||||||
# that's assumed if it doesn't exist.
|
# that's assumed if it doesn't exist.
|
||||||
if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
|
if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
|
||||||
|
@ -136,7 +116,9 @@ class Command(NoArgsCommand):
|
||||||
if extra_params:
|
if extra_params:
|
||||||
if not field_desc.endswith('('):
|
if not field_desc.endswith('('):
|
||||||
field_desc += ', '
|
field_desc += ', '
|
||||||
field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
|
field_desc += ', '.join([
|
||||||
|
'%s=%s' % (k, strip_prefix(repr(v)))
|
||||||
|
for k, v in extra_params.items()])
|
||||||
field_desc += ')'
|
field_desc += ')'
|
||||||
if comment_notes:
|
if comment_notes:
|
||||||
field_desc += ' # ' + ' '.join(comment_notes)
|
field_desc += ' # ' + ' '.join(comment_notes)
|
||||||
|
@ -144,6 +126,62 @@ class Command(NoArgsCommand):
|
||||||
for meta_line in self.get_meta(table_name):
|
for meta_line in self.get_meta(table_name):
|
||||||
yield meta_line
|
yield meta_line
|
||||||
|
|
||||||
|
def normalize_col_name(self, col_name, used_column_names, is_relation):
|
||||||
|
"""
|
||||||
|
Modify the column name to make it Python-compatible as a field name
|
||||||
|
"""
|
||||||
|
field_params = {}
|
||||||
|
field_notes = []
|
||||||
|
|
||||||
|
new_name = col_name.lower()
|
||||||
|
if new_name != col_name:
|
||||||
|
field_notes.append('Field name made lowercase.')
|
||||||
|
|
||||||
|
if is_relation:
|
||||||
|
if new_name.endswith('_id'):
|
||||||
|
new_name = new_name[:-3]
|
||||||
|
else:
|
||||||
|
field_params['db_column'] = col_name
|
||||||
|
|
||||||
|
new_name, num_repl = re.subn(r'\W', '_', new_name)
|
||||||
|
if num_repl > 0:
|
||||||
|
field_notes.append('Field renamed to remove unsuitable characters.')
|
||||||
|
|
||||||
|
if new_name.find('__') >= 0:
|
||||||
|
while new_name.find('__') >= 0:
|
||||||
|
new_name = new_name.replace('__', '_')
|
||||||
|
if col_name.lower().find('__') >= 0:
|
||||||
|
# Only add the comment if the double underscore was in the original name
|
||||||
|
field_notes.append("Field renamed because it contained more than one '_' in a row.")
|
||||||
|
|
||||||
|
if new_name.startswith('_'):
|
||||||
|
new_name = 'field%s' % new_name
|
||||||
|
field_notes.append("Field renamed because it started with '_'.")
|
||||||
|
|
||||||
|
if new_name.endswith('_'):
|
||||||
|
new_name = '%sfield' % new_name
|
||||||
|
field_notes.append("Field renamed because it ended with '_'.")
|
||||||
|
|
||||||
|
if keyword.iskeyword(new_name):
|
||||||
|
new_name += '_field'
|
||||||
|
field_notes.append('Field renamed because it was a Python reserved word.')
|
||||||
|
|
||||||
|
if new_name[0].isdigit():
|
||||||
|
new_name = 'number_%s' % new_name
|
||||||
|
field_notes.append("Field renamed because it wasn't a valid Python identifier.")
|
||||||
|
|
||||||
|
if new_name in used_column_names:
|
||||||
|
num = 0
|
||||||
|
while '%s_%d' % (new_name, num) in used_column_names:
|
||||||
|
num += 1
|
||||||
|
new_name = '%s_%d' % (new_name, num)
|
||||||
|
field_notes.append('Field renamed because of name conflict.')
|
||||||
|
|
||||||
|
if col_name != new_name and field_notes:
|
||||||
|
field_params['db_column'] = col_name
|
||||||
|
|
||||||
|
return new_name, field_params, field_notes
|
||||||
|
|
||||||
def get_field_type(self, connection, table_name, row):
|
def get_field_type(self, connection, table_name, row):
|
||||||
"""
|
"""
|
||||||
Given the database connection, the table name, and the cursor row
|
Given the database connection, the table name, and the cursor row
|
||||||
|
@ -181,6 +219,6 @@ class Command(NoArgsCommand):
|
||||||
to construct the inner Meta class for the model corresponding
|
to construct the inner Meta class for the model corresponding
|
||||||
to the given database table name.
|
to the given database table name.
|
||||||
"""
|
"""
|
||||||
return [' class Meta:',
|
return [" class Meta:",
|
||||||
' db_table = %r' % table_name,
|
" db_table = '%s'" % table_name,
|
||||||
'']
|
""]
|
||||||
|
|
|
@ -196,6 +196,10 @@ class Command(BaseCommand):
|
||||||
loaded_object_count += loaded_objects_in_fixture
|
loaded_object_count += loaded_objects_in_fixture
|
||||||
fixture_object_count += objects_in_fixture
|
fixture_object_count += objects_in_fixture
|
||||||
label_found = True
|
label_found = True
|
||||||
|
except Exception as e:
|
||||||
|
if not isinstance(e, CommandError):
|
||||||
|
e.args = ("Problem installing fixture '%s': %s" % (full_path, e),)
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
fixture.close()
|
fixture.close()
|
||||||
|
|
||||||
|
@ -209,7 +213,11 @@ class Command(BaseCommand):
|
||||||
# Since we disabled constraint checks, we must manually check for
|
# Since we disabled constraint checks, we must manually check for
|
||||||
# any invalid keys that might have been added
|
# any invalid keys that might have been added
|
||||||
table_names = [model._meta.db_table for model in models]
|
table_names = [model._meta.db_table for model in models]
|
||||||
connection.check_constraints(table_names=table_names)
|
try:
|
||||||
|
connection.check_constraints(table_names=table_names)
|
||||||
|
except Exception as e:
|
||||||
|
e.args = ("Problem installing fixtures: %s" % e,)
|
||||||
|
raise
|
||||||
|
|
||||||
except (SystemExit, KeyboardInterrupt):
|
except (SystemExit, KeyboardInterrupt):
|
||||||
raise
|
raise
|
||||||
|
@ -217,8 +225,6 @@ class Command(BaseCommand):
|
||||||
if commit:
|
if commit:
|
||||||
transaction.rollback(using=using)
|
transaction.rollback(using=using)
|
||||||
transaction.leave_transaction_management(using=using)
|
transaction.leave_transaction_management(using=using)
|
||||||
if not isinstance(e, CommandError):
|
|
||||||
e.args = ("Problem installing fixture '%s': %s" % (full_path, e),)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# If we found even one object in a fixture, we need to reset the
|
# If we found even one object in a fixture, we need to reset the
|
||||||
|
|
|
@ -47,31 +47,27 @@ def _popen(cmd):
|
||||||
output, errors = p.communicate()
|
output, errors = p.communicate()
|
||||||
return output, errors, p.returncode
|
return output, errors, p.returncode
|
||||||
|
|
||||||
def walk(root, topdown=True, onerror=None, followlinks=False,
|
def find_files(root, ignore_patterns, verbosity, stdout=sys.stdout, symlinks=False):
|
||||||
ignore_patterns=None, verbosity=0, stdout=sys.stdout):
|
|
||||||
"""
|
"""
|
||||||
A version of os.walk that can follow symlinks for Python < 2.6
|
Helper function to get all files in the given root.
|
||||||
"""
|
"""
|
||||||
if ignore_patterns is None:
|
|
||||||
ignore_patterns = []
|
|
||||||
dir_suffix = '%s*' % os.sep
|
dir_suffix = '%s*' % os.sep
|
||||||
norm_patterns = [p[:-len(dir_suffix)] if p.endswith(dir_suffix) else p for p in ignore_patterns]
|
norm_patterns = [p[:-len(dir_suffix)] if p.endswith(dir_suffix) else p for p in ignore_patterns]
|
||||||
for dirpath, dirnames, filenames in os.walk(root, topdown, onerror):
|
all_files = []
|
||||||
remove_dirs = []
|
for dirpath, dirnames, filenames in os.walk(root, topdown=True, followlinks=symlinks):
|
||||||
for dirname in dirnames:
|
for dirname in dirnames[:]:
|
||||||
if is_ignored(os.path.normpath(os.path.join(dirpath, dirname)), norm_patterns):
|
if is_ignored(os.path.normpath(os.path.join(dirpath, dirname)), norm_patterns):
|
||||||
remove_dirs.append(dirname)
|
dirnames.remove(dirname)
|
||||||
for dirname in remove_dirs:
|
if verbosity > 1:
|
||||||
dirnames.remove(dirname)
|
stdout.write('ignoring directory %s\n' % dirname)
|
||||||
if verbosity > 1:
|
for filename in filenames:
|
||||||
stdout.write('ignoring directory %s\n' % dirname)
|
if is_ignored(os.path.normpath(os.path.join(dirpath, filename)), ignore_patterns):
|
||||||
yield (dirpath, dirnames, filenames)
|
if verbosity > 1:
|
||||||
if followlinks:
|
stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
|
||||||
for d in dirnames:
|
else:
|
||||||
p = os.path.join(dirpath, d)
|
all_files.extend([(dirpath, filename)])
|
||||||
if os.path.islink(p):
|
all_files.sort()
|
||||||
for link_dirpath, link_dirnames, link_filenames in walk(p):
|
return all_files
|
||||||
yield (link_dirpath, link_dirnames, link_filenames)
|
|
||||||
|
|
||||||
def is_ignored(path, ignore_patterns):
|
def is_ignored(path, ignore_patterns):
|
||||||
"""
|
"""
|
||||||
|
@ -82,23 +78,6 @@ def is_ignored(path, ignore_patterns):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def find_files(root, ignore_patterns, verbosity, stdout=sys.stdout, symlinks=False):
|
|
||||||
"""
|
|
||||||
Helper function to get all files in the given root.
|
|
||||||
"""
|
|
||||||
all_files = []
|
|
||||||
for (dirpath, dirnames, filenames) in walk(root, followlinks=symlinks,
|
|
||||||
ignore_patterns=ignore_patterns, verbosity=verbosity, stdout=stdout):
|
|
||||||
for filename in filenames:
|
|
||||||
norm_filepath = os.path.normpath(os.path.join(dirpath, filename))
|
|
||||||
if is_ignored(norm_filepath, ignore_patterns):
|
|
||||||
if verbosity > 1:
|
|
||||||
stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
|
|
||||||
else:
|
|
||||||
all_files.extend([(dirpath, filename)])
|
|
||||||
all_files.sort()
|
|
||||||
return all_files
|
|
||||||
|
|
||||||
def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):
|
def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):
|
||||||
"""
|
"""
|
||||||
Copies plural forms header contents from a Django catalog of locale to
|
Copies plural forms header contents from a Django catalog of locale to
|
||||||
|
|
|
@ -80,14 +80,14 @@ class Command(NoArgsCommand):
|
||||||
readline.parse_and_bind("tab:complete")
|
readline.parse_and_bind("tab:complete")
|
||||||
|
|
||||||
# We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
|
# We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
|
||||||
# conventions and get $PYTHONSTARTUP first then import user.
|
# conventions and get $PYTHONSTARTUP first then .pythonrc.py.
|
||||||
if not use_plain:
|
if not use_plain:
|
||||||
pythonrc = os.environ.get("PYTHONSTARTUP")
|
for pythonrc in (os.environ.get("PYTHONSTARTUP"),
|
||||||
if pythonrc and os.path.isfile(pythonrc):
|
os.path.expanduser('~/.pythonrc.py')):
|
||||||
try:
|
if pythonrc and os.path.isfile(pythonrc):
|
||||||
execfile(pythonrc)
|
try:
|
||||||
except NameError:
|
with open(pythonrc) as handle:
|
||||||
pass
|
exec(compile(handle.read(), pythonrc, 'exec'))
|
||||||
# This will import .pythonrc.py as a side-effect
|
except NameError:
|
||||||
import user
|
pass
|
||||||
code.interact(local=imported_objects)
|
code.interact(local=imported_objects)
|
||||||
|
|
|
@ -8,6 +8,8 @@ import shutil
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import codecs
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
except ImportError: # Python 2
|
except ImportError: # Python 2
|
||||||
|
@ -154,12 +156,12 @@ class TemplateCommand(BaseCommand):
|
||||||
|
|
||||||
# Only render the Python files, as we don't want to
|
# Only render the Python files, as we don't want to
|
||||||
# accidentally render Django templates files
|
# accidentally render Django templates files
|
||||||
with open(old_path, 'r') as template_file:
|
with codecs.open(old_path, 'r', 'utf-8') as template_file:
|
||||||
content = template_file.read()
|
content = template_file.read()
|
||||||
if filename.endswith(extensions) or filename in extra_files:
|
if filename.endswith(extensions) or filename in extra_files:
|
||||||
template = Template(content)
|
template = Template(content)
|
||||||
content = template.render(context)
|
content = template.render(context)
|
||||||
with open(new_path, 'w') as new_file:
|
with codecs.open(new_path, 'w', 'utf-8') as new_file:
|
||||||
new_file.write(content)
|
new_file.write(content)
|
||||||
|
|
||||||
if self.verbosity >= 2:
|
if self.verbosity >= 2:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django.core.management.color import color_style
|
from django.core.management.color import color_style
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.itercompat import is_iterable
|
from django.utils.itercompat import is_iterable
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class ModelErrorCollection:
|
||||||
|
|
||||||
def add(self, context, error):
|
def add(self, context, error):
|
||||||
self.errors.append((context, error))
|
self.errors.append((context, error))
|
||||||
self.outfile.write(self.style.ERROR(smart_str("%s: %s\n" % (context, error))))
|
self.outfile.write(self.style.ERROR(force_str("%s: %s\n" % (context, error))))
|
||||||
|
|
||||||
|
|
||||||
def get_validation_errors(outfile, app=None):
|
def get_validation_errors(outfile, app=None):
|
||||||
|
|
|
@ -12,7 +12,6 @@ import json
|
||||||
from django.core.serializers.base import DeserializationError
|
from django.core.serializers.base import DeserializationError
|
||||||
from django.core.serializers.python import Serializer as PythonSerializer
|
from django.core.serializers.python import Serializer as PythonSerializer
|
||||||
from django.core.serializers.python import Deserializer as PythonDeserializer
|
from django.core.serializers.python import Deserializer as PythonDeserializer
|
||||||
from django.utils.encoding import smart_bytes
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.timezone import is_aware
|
from django.utils.timezone import is_aware
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ from django.db import models
|
||||||
from django.core.serializers.base import DeserializationError
|
from django.core.serializers.base import DeserializationError
|
||||||
from django.core.serializers.python import Serializer as PythonSerializer
|
from django.core.serializers.python import Serializer as PythonSerializer
|
||||||
from django.core.serializers.python import Deserializer as PythonDeserializer
|
from django.core.serializers.python import Deserializer as PythonDeserializer
|
||||||
from django.utils.encoding import smart_bytes
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ start of the base64 JSON.
|
||||||
There are 65 url-safe characters: the 64 used by url-safe base64 and the ':'.
|
There are 65 url-safe characters: the 64 used by url-safe base64 and the ':'.
|
||||||
These functions make use of all of them.
|
These functions make use of all of them.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
@ -43,7 +44,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils import baseconv
|
from django.utils import baseconv
|
||||||
from django.utils.crypto import constant_time_compare, salted_hmac
|
from django.utils.crypto import constant_time_compare, salted_hmac
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes, force_str, force_text
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,12 +63,12 @@ class SignatureExpired(BadSignature):
|
||||||
|
|
||||||
|
|
||||||
def b64_encode(s):
|
def b64_encode(s):
|
||||||
return base64.urlsafe_b64encode(smart_bytes(s)).decode('ascii').strip('=')
|
return base64.urlsafe_b64encode(s).strip(b'=')
|
||||||
|
|
||||||
|
|
||||||
def b64_decode(s):
|
def b64_decode(s):
|
||||||
pad = '=' * (-len(s) % 4)
|
pad = b'=' * (-len(s) % 4)
|
||||||
return base64.urlsafe_b64decode(smart_bytes(s + pad)).decode('ascii')
|
return base64.urlsafe_b64decode(s + pad)
|
||||||
|
|
||||||
|
|
||||||
def base64_hmac(salt, value, key):
|
def base64_hmac(salt, value, key):
|
||||||
|
@ -116,20 +117,20 @@ def dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer,
|
||||||
value or re-using a salt value across different parts of your
|
value or re-using a salt value across different parts of your
|
||||||
application without good cause is a security risk.
|
application without good cause is a security risk.
|
||||||
"""
|
"""
|
||||||
data = serializer().dumps(obj)
|
data = force_bytes(serializer().dumps(obj))
|
||||||
|
|
||||||
# Flag for if it's been compressed or not
|
# Flag for if it's been compressed or not
|
||||||
is_compressed = False
|
is_compressed = False
|
||||||
|
|
||||||
if compress:
|
if compress:
|
||||||
# Avoid zlib dependency unless compress is being used
|
# Avoid zlib dependency unless compress is being used
|
||||||
compressed = zlib.compress(smart_bytes(data))
|
compressed = zlib.compress(data)
|
||||||
if len(compressed) < (len(data) - 1):
|
if len(compressed) < (len(data) - 1):
|
||||||
data = compressed
|
data = compressed
|
||||||
is_compressed = True
|
is_compressed = True
|
||||||
base64d = b64_encode(data)
|
base64d = b64_encode(data)
|
||||||
if is_compressed:
|
if is_compressed:
|
||||||
base64d = '.' + base64d
|
base64d = b'.' + base64d
|
||||||
return TimestampSigner(key, salt=salt).sign(base64d)
|
return TimestampSigner(key, salt=salt).sign(base64d)
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,37 +138,45 @@ def loads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, ma
|
||||||
"""
|
"""
|
||||||
Reverse of dumps(), raises BadSignature if signature fails
|
Reverse of dumps(), raises BadSignature if signature fails
|
||||||
"""
|
"""
|
||||||
base64d = TimestampSigner(key, salt=salt).unsign(s, max_age=max_age)
|
# TimestampSigner.unsign always returns unicode but base64 and zlib
|
||||||
|
# compression operate on bytes.
|
||||||
|
base64d = force_bytes(TimestampSigner(key, salt=salt).unsign(s, max_age=max_age))
|
||||||
decompress = False
|
decompress = False
|
||||||
if base64d[0] == '.':
|
if base64d[0] == b'.':
|
||||||
# It's compressed; uncompress it first
|
# It's compressed; uncompress it first
|
||||||
base64d = base64d[1:]
|
base64d = base64d[1:]
|
||||||
decompress = True
|
decompress = True
|
||||||
data = b64_decode(base64d)
|
data = b64_decode(base64d)
|
||||||
if decompress:
|
if decompress:
|
||||||
data = zlib.decompress(data)
|
data = zlib.decompress(data)
|
||||||
return serializer().loads(data)
|
return serializer().loads(force_str(data))
|
||||||
|
|
||||||
|
|
||||||
class Signer(object):
|
class Signer(object):
|
||||||
|
|
||||||
def __init__(self, key=None, sep=':', salt=None):
|
def __init__(self, key=None, sep=':', salt=None):
|
||||||
self.sep = sep
|
# Use of native strings in all versions of Python
|
||||||
self.key = key or settings.SECRET_KEY
|
self.sep = str(sep)
|
||||||
self.salt = salt or ('%s.%s' %
|
self.key = str(key or settings.SECRET_KEY)
|
||||||
(self.__class__.__module__, self.__class__.__name__))
|
self.salt = str(salt or
|
||||||
|
'%s.%s' % (self.__class__.__module__, self.__class__.__name__))
|
||||||
|
|
||||||
def signature(self, value):
|
def signature(self, value):
|
||||||
return base64_hmac(self.salt + 'signer', value, self.key)
|
signature = base64_hmac(self.salt + 'signer', value, self.key)
|
||||||
|
# Convert the signature from bytes to str only on Python 3
|
||||||
|
return force_str(signature)
|
||||||
|
|
||||||
def sign(self, value):
|
def sign(self, value):
|
||||||
return '%s%s%s' % (value, self.sep, self.signature(value))
|
value = force_str(value)
|
||||||
|
return str('%s%s%s') % (value, self.sep, self.signature(value))
|
||||||
|
|
||||||
def unsign(self, signed_value):
|
def unsign(self, signed_value):
|
||||||
|
signed_value = force_str(signed_value)
|
||||||
if not self.sep in signed_value:
|
if not self.sep in signed_value:
|
||||||
raise BadSignature('No "%s" found in value' % self.sep)
|
raise BadSignature('No "%s" found in value' % self.sep)
|
||||||
value, sig = signed_value.rsplit(self.sep, 1)
|
value, sig = signed_value.rsplit(self.sep, 1)
|
||||||
if constant_time_compare(sig, self.signature(value)):
|
if constant_time_compare(sig, self.signature(value)):
|
||||||
return value
|
return force_text(value)
|
||||||
raise BadSignature('Signature "%s" does not match' % sig)
|
raise BadSignature('Signature "%s" does not match' % sig)
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,8 +186,9 @@ class TimestampSigner(Signer):
|
||||||
return baseconv.base62.encode(int(time.time()))
|
return baseconv.base62.encode(int(time.time()))
|
||||||
|
|
||||||
def sign(self, value):
|
def sign(self, value):
|
||||||
value = '%s%s%s' % (value, self.sep, self.timestamp())
|
value = force_str(value)
|
||||||
return '%s%s%s' % (value, self.sep, self.signature(value))
|
value = str('%s%s%s') % (value, self.sep, self.timestamp())
|
||||||
|
return super(TimestampSigner, self).sign(value)
|
||||||
|
|
||||||
def unsign(self, value, max_age=None):
|
def unsign(self, value, max_age=None):
|
||||||
result = super(TimestampSigner, self).unsign(value)
|
result = super(TimestampSigner, self).unsign(value)
|
||||||
|
|
|
@ -14,7 +14,7 @@ from threading import local
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.encoding import iri_to_uri, force_text, smart_str
|
from django.utils.encoding import force_str, force_text, iri_to_uri
|
||||||
from django.utils.functional import memoize, lazy
|
from django.utils.functional import memoize, lazy
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.module_loading import module_has_submodule
|
from django.utils.module_loading import module_has_submodule
|
||||||
|
@ -195,7 +195,7 @@ class RegexURLPattern(LocaleRegexProvider):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
|
return force_str('<%s %s %s>' % (self.__class__.__name__, self.name, self.regex.pattern))
|
||||||
|
|
||||||
def add_prefix(self, prefix):
|
def add_prefix(self, prefix):
|
||||||
"""
|
"""
|
||||||
|
@ -245,8 +245,13 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||||
self._app_dict = {}
|
self._app_dict = {}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<%s %s (%s:%s) %s>' % (
|
if isinstance(self.urlconf_name, list) and len(self.urlconf_name):
|
||||||
self.__class__.__name__, self.urlconf_name, self.app_name,
|
# Don't bother to output the whole list, it can be huge
|
||||||
|
urlconf_repr = '<%s list>' % self.urlconf_name[0].__class__.__name__
|
||||||
|
else:
|
||||||
|
urlconf_repr = repr(self.urlconf_name)
|
||||||
|
return force_str('<%s %s (%s:%s) %s>' % (
|
||||||
|
self.__class__.__name__, urlconf_repr, self.app_name,
|
||||||
self.namespace, self.regex.pattern))
|
self.namespace, self.regex.pattern))
|
||||||
|
|
||||||
def _populate(self):
|
def _populate(self):
|
||||||
|
|
|
@ -8,7 +8,7 @@ except ImportError: # Python 2
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.ipv6 import is_valid_ipv6_address
|
from django.utils.ipv6 import is_valid_ipv6_address
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class RegexValidator(object):
|
||||||
"""
|
"""
|
||||||
Validates that the input matches the regular expression.
|
Validates that the input matches the regular expression.
|
||||||
"""
|
"""
|
||||||
if not self.regex.search(smart_text(value)):
|
if not self.regex.search(force_text(value)):
|
||||||
raise ValidationError(self.message, code=self.code)
|
raise ValidationError(self.message, code=self.code)
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ class URLValidator(RegexValidator):
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
# Trivial case failed. Try for possible IDN domain
|
# Trivial case failed. Try for possible IDN domain
|
||||||
if value:
|
if value:
|
||||||
value = smart_text(value)
|
value = force_text(value)
|
||||||
scheme, netloc, path, query, fragment = urlsplit(value)
|
scheme, netloc, path, query, fragment = urlsplit(value)
|
||||||
try:
|
try:
|
||||||
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
|
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
|
||||||
|
|
|
@ -609,7 +609,7 @@ class BaseDatabaseOperations(object):
|
||||||
exists for database backends to provide a better implementation
|
exists for database backends to provide a better implementation
|
||||||
according to their own quoting schemes.
|
according to their own quoting schemes.
|
||||||
"""
|
"""
|
||||||
from django.utils.encoding import smart_text, force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
# Convert params to contain Unicode values.
|
# Convert params to contain Unicode values.
|
||||||
to_unicode = lambda s: force_text(s, strings_only=True, errors='replace')
|
to_unicode = lambda s: force_text(s, strings_only=True, errors='replace')
|
||||||
|
@ -618,7 +618,7 @@ class BaseDatabaseOperations(object):
|
||||||
else:
|
else:
|
||||||
u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
|
u_params = dict([(to_unicode(k), to_unicode(v)) for k, v in params.items()])
|
||||||
|
|
||||||
return smart_text(sql) % u_params
|
return force_text(sql) % u_params
|
||||||
|
|
||||||
def last_insert_id(self, cursor, table_name, pk_name):
|
def last_insert_id(self, cursor, table_name, pk_name):
|
||||||
"""
|
"""
|
||||||
|
@ -802,8 +802,8 @@ class BaseDatabaseOperations(object):
|
||||||
|
|
||||||
def prep_for_like_query(self, x):
|
def prep_for_like_query(self, x):
|
||||||
"""Prepares a value for use in a LIKE query."""
|
"""Prepares a value for use in a LIKE query."""
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import force_text
|
||||||
return smart_text(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
|
return force_text(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_")
|
||||||
|
|
||||||
# Same as prep_for_like_query(), but called for "iexact" matches, which
|
# Same as prep_for_like_query(), but called for "iexact" matches, which
|
||||||
# need not necessarily be implemented using "LIKE" in the backend.
|
# need not necessarily be implemented using "LIKE" in the backend.
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
|
try:
|
||||||
|
from itertools import zip_longest
|
||||||
|
except ImportError:
|
||||||
|
from itertools import izip_longest as zip_longest
|
||||||
|
|
||||||
from django.db.models.sql import compiler
|
from django.db.models.sql import compiler
|
||||||
|
|
||||||
|
|
||||||
class SQLCompiler(compiler.SQLCompiler):
|
class SQLCompiler(compiler.SQLCompiler):
|
||||||
def resolve_columns(self, row, fields=()):
|
def resolve_columns(self, row, fields=()):
|
||||||
values = []
|
values = []
|
||||||
index_extra_select = len(self.query.extra_select)
|
index_extra_select = len(self.query.extra_select)
|
||||||
for value, field in map(None, row[index_extra_select:], fields):
|
for value, field in zip_longest(row[index_extra_select:], fields):
|
||||||
if (field and field.get_internal_type() in ("BooleanField", "NullBooleanField") and
|
if (field and field.get_internal_type() in ("BooleanField", "NullBooleanField") and
|
||||||
value in (0, 1)):
|
value in (0, 1)):
|
||||||
value = bool(value)
|
value = bool(value)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import re
|
||||||
|
from .base import FIELD_TYPE
|
||||||
|
|
||||||
from django.db.backends import BaseDatabaseIntrospection
|
from django.db.backends import BaseDatabaseIntrospection
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from MySQLdb import ProgrammingError, OperationalError
|
|
||||||
from MySQLdb.constants import FIELD_TYPE
|
|
||||||
import re
|
|
||||||
|
|
||||||
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
|
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)")
|
||||||
|
|
||||||
|
@ -35,9 +36,20 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
return [row[0] for row in cursor.fetchall()]
|
return [row[0] for row in cursor.fetchall()]
|
||||||
|
|
||||||
def get_table_description(self, cursor, table_name):
|
def get_table_description(self, cursor, table_name):
|
||||||
"Returns a description of the table, with the DB-API cursor.description interface."
|
"""
|
||||||
|
Returns a description of the table, with the DB-API cursor.description interface."
|
||||||
|
"""
|
||||||
|
# varchar length returned by cursor.description is an internal length,
|
||||||
|
# not visible length (#5725), use information_schema database to fix this
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT column_name, character_maximum_length FROM information_schema.columns
|
||||||
|
WHERE table_name = %s AND table_schema = DATABASE()
|
||||||
|
AND character_maximum_length IS NOT NULL""", [table_name])
|
||||||
|
length_map = dict(cursor.fetchall())
|
||||||
|
|
||||||
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
|
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
|
||||||
return cursor.description
|
return [line[:3] + (length_map.get(line[0], line[3]),) + line[4:]
|
||||||
|
for line in cursor.description]
|
||||||
|
|
||||||
def _name_to_index(self, cursor, table_name):
|
def _name_to_index(self, cursor, table_name):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -10,8 +10,6 @@ import decimal
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
def _setup_environment(environ):
|
def _setup_environment(environ):
|
||||||
import platform
|
import platform
|
||||||
# Cygwin requires some special voodoo to set the environment variables
|
# Cygwin requires some special voodoo to set the environment variables
|
||||||
|
@ -53,7 +51,7 @@ from django.db.backends.signals import connection_created
|
||||||
from django.db.backends.oracle.client import DatabaseClient
|
from django.db.backends.oracle.client import DatabaseClient
|
||||||
from django.db.backends.oracle.creation import DatabaseCreation
|
from django.db.backends.oracle.creation import DatabaseCreation
|
||||||
from django.db.backends.oracle.introspection import DatabaseIntrospection
|
from django.db.backends.oracle.introspection import DatabaseIntrospection
|
||||||
from django.utils.encoding import smart_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
@ -66,7 +64,7 @@ IntegrityError = Database.IntegrityError
|
||||||
if int(Database.version.split('.', 1)[0]) >= 5 and not hasattr(Database, 'UNICODE'):
|
if int(Database.version.split('.', 1)[0]) >= 5 and not hasattr(Database, 'UNICODE'):
|
||||||
convert_unicode = force_text
|
convert_unicode = force_text
|
||||||
else:
|
else:
|
||||||
convert_unicode = smart_bytes
|
convert_unicode = force_bytes
|
||||||
|
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
|
@ -604,9 +602,9 @@ class OracleParam(object):
|
||||||
elif param is False:
|
elif param is False:
|
||||||
param = "0"
|
param = "0"
|
||||||
if hasattr(param, 'bind_parameter'):
|
if hasattr(param, 'bind_parameter'):
|
||||||
self.smart_bytes = param.bind_parameter(cursor)
|
self.force_bytes = param.bind_parameter(cursor)
|
||||||
else:
|
else:
|
||||||
self.smart_bytes = convert_unicode(param, cursor.charset,
|
self.force_bytes = convert_unicode(param, cursor.charset,
|
||||||
strings_only)
|
strings_only)
|
||||||
if hasattr(param, 'input_size'):
|
if hasattr(param, 'input_size'):
|
||||||
# If parameter has `input_size` attribute, use that.
|
# If parameter has `input_size` attribute, use that.
|
||||||
|
@ -685,7 +683,7 @@ class FormatStylePlaceholderCursor(object):
|
||||||
self.setinputsizes(*sizes)
|
self.setinputsizes(*sizes)
|
||||||
|
|
||||||
def _param_generator(self, params):
|
def _param_generator(self, params):
|
||||||
return [p.smart_bytes for p in params]
|
return [p.force_bytes for p in params]
|
||||||
|
|
||||||
def execute(self, query, params=None):
|
def execute(self, query, params=None):
|
||||||
if params is None:
|
if params is None:
|
||||||
|
|
|
@ -45,8 +45,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
WHERE table_name = %s""", [table_name])
|
WHERE table_name = %s""", [table_name])
|
||||||
null_map = dict(cursor.fetchall())
|
null_map = dict(cursor.fetchall())
|
||||||
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
|
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
|
||||||
return [tuple([item for item in line[:6]] + [null_map[line[0]]=='YES'])
|
return [line[:6] + (null_map[line[0]]=='YES',)
|
||||||
for line in cursor.description]
|
for line in cursor.description]
|
||||||
|
|
||||||
def get_relations(self, cursor, table_name):
|
def get_relations(self, cursor, table_name):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
import re
|
import re
|
||||||
from django.db.backends import BaseDatabaseIntrospection
|
from django.db.backends import BaseDatabaseIntrospection
|
||||||
|
|
||||||
|
field_size_re = re.compile(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$')
|
||||||
|
|
||||||
|
def get_field_size(name):
|
||||||
|
""" Extract the size number from a "varchar(11)" type name """
|
||||||
|
m = field_size_re.search(name)
|
||||||
|
return int(m.group(1)) if m else None
|
||||||
|
|
||||||
|
|
||||||
# This light wrapper "fakes" a dictionary interface, because some SQLite data
|
# This light wrapper "fakes" a dictionary interface, because some SQLite data
|
||||||
# types include variables in them -- e.g. "varchar(30)" -- and can't be matched
|
# types include variables in them -- e.g. "varchar(30)" -- and can't be matched
|
||||||
# as a simple dictionary lookup.
|
# as a simple dictionary lookup.
|
||||||
|
@ -32,10 +40,9 @@ class FlexibleFieldLookupDict(object):
|
||||||
try:
|
try:
|
||||||
return self.base_data_types_reverse[key]
|
return self.base_data_types_reverse[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
import re
|
size = get_field_size(key)
|
||||||
m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key)
|
if size is not None:
|
||||||
if m:
|
return ('CharField', {'max_length': size})
|
||||||
return ('CharField', {'max_length': int(m.group(1))})
|
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
class DatabaseIntrospection(BaseDatabaseIntrospection):
|
class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
|
@ -53,7 +60,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
|
|
||||||
def get_table_description(self, cursor, table_name):
|
def get_table_description(self, cursor, table_name):
|
||||||
"Returns a description of the table, with the DB-API cursor.description interface."
|
"Returns a description of the table, with the DB-API cursor.description interface."
|
||||||
return [(info['name'], info['type'], None, None, None, None,
|
return [(info['name'], info['type'], None, info['size'], None, None,
|
||||||
info['null_ok']) for info in self._table_info(cursor, table_name)]
|
info['null_ok']) for info in self._table_info(cursor, table_name)]
|
||||||
|
|
||||||
def get_relations(self, cursor, table_name):
|
def get_relations(self, cursor, table_name):
|
||||||
|
@ -171,6 +178,7 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
||||||
# cid, name, type, notnull, dflt_value, pk
|
# cid, name, type, notnull, dflt_value, pk
|
||||||
return [{'name': field[1],
|
return [{'name': field[1],
|
||||||
'type': field[2],
|
'type': field[2],
|
||||||
|
'size': get_field_size(field[2]),
|
||||||
'null_ok': not field[3],
|
'null_ok': not field[3],
|
||||||
'pk': field[5] # undocumented
|
'pk': field[5] # undocumented
|
||||||
} for field in cursor.fetchall()]
|
} for field in cursor.fetchall()]
|
||||||
|
|
|
@ -6,7 +6,7 @@ import hashlib
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ def truncate_name(name, length=None, hash_len=4):
|
||||||
if length is None or len(name) <= length:
|
if length is None or len(name) <= length:
|
||||||
return name
|
return name
|
||||||
|
|
||||||
hsh = hashlib.md5(smart_bytes(name)).hexdigest()[:hash_len]
|
hsh = hashlib.md5(force_bytes(name)).hexdigest()[:hash_len]
|
||||||
return '%s%s' % (name[:length-hash_len], hsh)
|
return '%s%s' % (name[:length-hash_len], hsh)
|
||||||
|
|
||||||
def format_number(value, max_digits, decimal_places):
|
def format_number(value, max_digits, decimal_places):
|
||||||
|
|
|
@ -23,7 +23,7 @@ from django.db.models import signals
|
||||||
from django.db.models.loading import register_models, get_model
|
from django.db.models.loading import register_models, get_model
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.utils.encoding import smart_str, force_text
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.text import get_text_list, capfirst
|
from django.utils.text import get_text_list, capfirst
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ class Model(six.with_metaclass(ModelBase, object)):
|
||||||
u = six.text_type(self)
|
u = six.text_type(self)
|
||||||
except (UnicodeEncodeError, UnicodeDecodeError):
|
except (UnicodeEncodeError, UnicodeDecodeError):
|
||||||
u = '[Bad Unicode data]'
|
u = '[Bad Unicode data]'
|
||||||
return smart_str('<%s: %s>' % (self.__class__.__name__, u))
|
return force_str('<%s: %s>' % (self.__class__.__name__, u))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if not six.PY3 and hasattr(self, '__unicode__'):
|
if not six.PY3 and hasattr(self, '__unicode__'):
|
||||||
|
|
|
@ -1047,13 +1047,14 @@ class GenericIPAddressField(Field):
|
||||||
description = _("IP address")
|
description = _("IP address")
|
||||||
default_error_messages = {}
|
default_error_messages = {}
|
||||||
|
|
||||||
def __init__(self, protocol='both', unpack_ipv4=False, *args, **kwargs):
|
def __init__(self, verbose_name=None, name=None, protocol='both',
|
||||||
|
unpack_ipv4=False, *args, **kwargs):
|
||||||
self.unpack_ipv4 = unpack_ipv4
|
self.unpack_ipv4 = unpack_ipv4
|
||||||
self.default_validators, invalid_error_message = \
|
self.default_validators, invalid_error_message = \
|
||||||
validators.ip_address_validators(protocol, unpack_ipv4)
|
validators.ip_address_validators(protocol, unpack_ipv4)
|
||||||
self.default_error_messages['invalid'] = invalid_error_message
|
self.default_error_messages['invalid'] = invalid_error_message
|
||||||
kwargs['max_length'] = 39
|
kwargs['max_length'] = 39
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, verbose_name, name, *args, **kwargs)
|
||||||
|
|
||||||
def get_internal_type(self):
|
def get_internal_type(self):
|
||||||
return "GenericIPAddressField"
|
return "GenericIPAddressField"
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.core.files.base import File
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
from django.core.files.images import ImageFile
|
from django.core.files.images import ImageFile
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from django.utils.encoding import force_text, smart_str
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ class FileField(Field):
|
||||||
setattr(cls, self.name, self.descriptor_class(self))
|
setattr(cls, self.name, self.descriptor_class(self))
|
||||||
|
|
||||||
def get_directory_name(self):
|
def get_directory_name(self):
|
||||||
return os.path.normpath(force_text(datetime.datetime.now().strftime(smart_str(self.upload_to))))
|
return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to))))
|
||||||
|
|
||||||
def get_filename(self, filename):
|
def get_filename(self, filename):
|
||||||
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
|
return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
|
||||||
|
|
|
@ -498,9 +498,7 @@ class QuerySet(object):
|
||||||
"Cannot use 'limit' or 'offset' with in_bulk"
|
"Cannot use 'limit' or 'offset' with in_bulk"
|
||||||
if not id_list:
|
if not id_list:
|
||||||
return {}
|
return {}
|
||||||
qs = self._clone()
|
qs = self.filter(pk__in=id_list).order_by()
|
||||||
qs.query.add_filter(('pk__in', id_list))
|
|
||||||
qs.query.clear_ordering(force_empty=True)
|
|
||||||
return dict([(obj._get_pk_val(), obj) for obj in qs])
|
return dict([(obj._get_pk_val(), obj) for obj in qs])
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
|
|
@ -470,9 +470,7 @@ class SQLCompiler(object):
|
||||||
# Must use left outer joins for nullable fields and their relations.
|
# Must use left outer joins for nullable fields and their relations.
|
||||||
# Ordering or distinct must not affect the returned set, and INNER
|
# Ordering or distinct must not affect the returned set, and INNER
|
||||||
# JOINS for nullable fields could do this.
|
# JOINS for nullable fields could do this.
|
||||||
if joins_to_promote:
|
self.query.promote_joins(joins_to_promote)
|
||||||
self.query.promote_alias_chain(joins_to_promote,
|
|
||||||
self.query.alias_map[joins_to_promote[0]].join_type == self.query.LOUTER)
|
|
||||||
return field, col, alias, joins, opts
|
return field, col, alias, joins, opts
|
||||||
|
|
||||||
def _final_join_removal(self, col, alias):
|
def _final_join_removal(self, col, alias):
|
||||||
|
@ -645,8 +643,6 @@ class SQLCompiler(object):
|
||||||
alias_chain.append(alias)
|
alias_chain.append(alias)
|
||||||
for (dupe_opts, dupe_col) in dupe_set:
|
for (dupe_opts, dupe_col) in dupe_set:
|
||||||
self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
|
self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias)
|
||||||
if self.query.alias_map[root_alias].join_type == self.query.LOUTER:
|
|
||||||
self.query.promote_alias_chain(alias_chain, True)
|
|
||||||
else:
|
else:
|
||||||
alias = root_alias
|
alias = root_alias
|
||||||
|
|
||||||
|
@ -663,8 +659,6 @@ class SQLCompiler(object):
|
||||||
columns, aliases = self.get_default_columns(start_alias=alias,
|
columns, aliases = self.get_default_columns(start_alias=alias,
|
||||||
opts=f.rel.to._meta, as_pairs=True)
|
opts=f.rel.to._meta, as_pairs=True)
|
||||||
self.query.related_select_cols.extend(columns)
|
self.query.related_select_cols.extend(columns)
|
||||||
if self.query.alias_map[alias].join_type == self.query.LOUTER:
|
|
||||||
self.query.promote_alias_chain(aliases, True)
|
|
||||||
self.query.related_select_fields.extend(f.rel.to._meta.fields)
|
self.query.related_select_fields.extend(f.rel.to._meta.fields)
|
||||||
if restricted:
|
if restricted:
|
||||||
next = requested.get(f.name, {})
|
next = requested.get(f.name, {})
|
||||||
|
@ -738,7 +732,9 @@ class SQLCompiler(object):
|
||||||
self.query.related_select_fields.extend(model._meta.fields)
|
self.query.related_select_fields.extend(model._meta.fields)
|
||||||
|
|
||||||
next = requested.get(f.related_query_name(), {})
|
next = requested.get(f.related_query_name(), {})
|
||||||
new_nullable = f.null or None
|
# Use True here because we are looking at the _reverse_ side of
|
||||||
|
# the relation, which is always nullable.
|
||||||
|
new_nullable = True
|
||||||
|
|
||||||
self.fill_related_selections(model._meta, table, cur_depth+1,
|
self.fill_related_selections(model._meta, table, cur_depth+1,
|
||||||
used, next, restricted, new_nullable)
|
used, next, restricted, new_nullable)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Valid query types (a dictionary is used for speedy lookups).
|
# Valid query types (a set is used for speedy lookups).
|
||||||
QUERY_TERMS = set([
|
QUERY_TERMS = set([
|
||||||
'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
|
'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
|
||||||
'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
|
'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
|
||||||
|
|
|
@ -505,7 +505,7 @@ class Query(object):
|
||||||
# Again, some of the tables won't have aliases due to
|
# Again, some of the tables won't have aliases due to
|
||||||
# the trimming of unnecessary tables.
|
# the trimming of unnecessary tables.
|
||||||
if self.alias_refcount.get(alias) or rhs.alias_refcount.get(alias):
|
if self.alias_refcount.get(alias) or rhs.alias_refcount.get(alias):
|
||||||
self.promote_alias(alias, True)
|
self.promote_joins([alias], True)
|
||||||
|
|
||||||
# Now relabel a copy of the rhs where-clause and add it to the current
|
# Now relabel a copy of the rhs where-clause and add it to the current
|
||||||
# one.
|
# one.
|
||||||
|
@ -682,32 +682,38 @@ class Query(object):
|
||||||
""" Decreases the reference count for this alias. """
|
""" Decreases the reference count for this alias. """
|
||||||
self.alias_refcount[alias] -= amount
|
self.alias_refcount[alias] -= amount
|
||||||
|
|
||||||
def promote_alias(self, alias, unconditional=False):
|
def promote_joins(self, aliases, unconditional=False):
|
||||||
"""
|
"""
|
||||||
Promotes the join type of an alias to an outer join if it's possible
|
Promotes recursively the join type of given aliases and its children to
|
||||||
for the join to contain NULL values on the left. If 'unconditional' is
|
an outer join. If 'unconditional' is False, the join is only promoted if
|
||||||
False, the join is only promoted if it is nullable, otherwise it is
|
it is nullable or the parent join is an outer join.
|
||||||
always promoted.
|
|
||||||
|
|
||||||
Returns True if the join was promoted by this call.
|
Note about join promotion: When promoting any alias, we make sure all
|
||||||
|
joins which start from that alias are promoted, too. When adding a join
|
||||||
|
in join(), we make sure any join added to already existing LOUTER join
|
||||||
|
is generated as LOUTER. This ensures we don't ever have broken join
|
||||||
|
chains which contain first a LOUTER join, then an INNER JOIN, that is
|
||||||
|
this kind of join should never be generated: a LOUTER b INNER c. The
|
||||||
|
reason for avoiding this type of join chain is that the INNER after
|
||||||
|
the LOUTER will effectively remove any effect the LOUTER had.
|
||||||
"""
|
"""
|
||||||
if ((unconditional or self.alias_map[alias].nullable) and
|
aliases = list(aliases)
|
||||||
self.alias_map[alias].join_type != self.LOUTER):
|
while aliases:
|
||||||
data = self.alias_map[alias]
|
alias = aliases.pop(0)
|
||||||
data = data._replace(join_type=self.LOUTER)
|
parent_alias = self.alias_map[alias].lhs_alias
|
||||||
self.alias_map[alias] = data
|
parent_louter = (parent_alias
|
||||||
return True
|
and self.alias_map[parent_alias].join_type == self.LOUTER)
|
||||||
return False
|
already_louter = self.alias_map[alias].join_type == self.LOUTER
|
||||||
|
if ((unconditional or self.alias_map[alias].nullable
|
||||||
def promote_alias_chain(self, chain, must_promote=False):
|
or parent_louter) and not already_louter):
|
||||||
"""
|
data = self.alias_map[alias]._replace(join_type=self.LOUTER)
|
||||||
Walks along a chain of aliases, promoting the first nullable join and
|
self.alias_map[alias] = data
|
||||||
any joins following that. If 'must_promote' is True, all the aliases in
|
# Join type of 'alias' changed, so re-examine all aliases that
|
||||||
the chain are promoted.
|
# refer to this one.
|
||||||
"""
|
aliases.extend(
|
||||||
for alias in chain:
|
join for join in self.alias_map.keys()
|
||||||
if self.promote_alias(alias, must_promote):
|
if (self.alias_map[join].lhs_alias == alias
|
||||||
must_promote = True
|
and join not in aliases))
|
||||||
|
|
||||||
def reset_refcounts(self, to_counts):
|
def reset_refcounts(self, to_counts):
|
||||||
"""
|
"""
|
||||||
|
@ -726,19 +732,10 @@ class Query(object):
|
||||||
then and which ones haven't been used and promotes all of those
|
then and which ones haven't been used and promotes all of those
|
||||||
aliases, plus any children of theirs in the alias tree, to outer joins.
|
aliases, plus any children of theirs in the alias tree, to outer joins.
|
||||||
"""
|
"""
|
||||||
# FIXME: There's some (a lot of!) overlap with the similar OR promotion
|
|
||||||
# in add_filter(). It's not quite identical, but is very similar. So
|
|
||||||
# pulling out the common bits is something for later.
|
|
||||||
considered = {}
|
|
||||||
for alias in self.tables:
|
for alias in self.tables:
|
||||||
if alias not in used_aliases:
|
if alias in used_aliases and (alias not in initial_refcounts or
|
||||||
continue
|
|
||||||
if (alias not in initial_refcounts or
|
|
||||||
self.alias_refcount[alias] == initial_refcounts[alias]):
|
self.alias_refcount[alias] == initial_refcounts[alias]):
|
||||||
parent = self.alias_map[alias].lhs_alias
|
self.promote_joins([alias])
|
||||||
must_promote = considered.get(parent, False)
|
|
||||||
promoted = self.promote_alias(alias, must_promote)
|
|
||||||
considered[alias] = must_promote or promoted
|
|
||||||
|
|
||||||
def change_aliases(self, change_map):
|
def change_aliases(self, change_map):
|
||||||
"""
|
"""
|
||||||
|
@ -875,6 +872,9 @@ class Query(object):
|
||||||
LOUTER join type. This is used when joining certain types of querysets
|
LOUTER join type. This is used when joining certain types of querysets
|
||||||
and Q-objects together.
|
and Q-objects together.
|
||||||
|
|
||||||
|
A join is always created as LOUTER if the lhs alias is LOUTER to make
|
||||||
|
sure we do not generate chains like a LOUTER b INNER c.
|
||||||
|
|
||||||
If 'nullable' is True, the join can potentially involve NULL values and
|
If 'nullable' is True, the join can potentially involve NULL values and
|
||||||
is a candidate for promotion (to "left outer") when combining querysets.
|
is a candidate for promotion (to "left outer") when combining querysets.
|
||||||
"""
|
"""
|
||||||
|
@ -900,8 +900,8 @@ class Query(object):
|
||||||
if self.alias_map[alias].lhs_alias != lhs:
|
if self.alias_map[alias].lhs_alias != lhs:
|
||||||
continue
|
continue
|
||||||
self.ref_alias(alias)
|
self.ref_alias(alias)
|
||||||
if promote:
|
if promote or (lhs and self.alias_map[lhs].join_type == self.LOUTER):
|
||||||
self.promote_alias(alias)
|
self.promote_joins([alias])
|
||||||
return alias
|
return alias
|
||||||
|
|
||||||
# No reuse is possible, so we need a new alias.
|
# No reuse is possible, so we need a new alias.
|
||||||
|
@ -910,7 +910,12 @@ class Query(object):
|
||||||
# Not all tables need to be joined to anything. No join type
|
# Not all tables need to be joined to anything. No join type
|
||||||
# means the later columns are ignored.
|
# means the later columns are ignored.
|
||||||
join_type = None
|
join_type = None
|
||||||
elif promote or outer_if_first:
|
elif (promote or outer_if_first
|
||||||
|
or self.alias_map[lhs].join_type == self.LOUTER):
|
||||||
|
# We need to use LOUTER join if asked by promote or outer_if_first,
|
||||||
|
# or if the LHS table is left-joined in the query. Adding inner join
|
||||||
|
# to an existing outer join effectively cancels the effect of the
|
||||||
|
# outer join.
|
||||||
join_type = self.LOUTER
|
join_type = self.LOUTER
|
||||||
else:
|
else:
|
||||||
join_type = self.INNER
|
join_type = self.INNER
|
||||||
|
@ -1004,8 +1009,7 @@ class Query(object):
|
||||||
# If the aggregate references a model or field that requires a join,
|
# If the aggregate references a model or field that requires a join,
|
||||||
# those joins must be LEFT OUTER - empty join rows must be returned
|
# those joins must be LEFT OUTER - empty join rows must be returned
|
||||||
# in order for zeros to be returned for those aggregates.
|
# in order for zeros to be returned for those aggregates.
|
||||||
for column_alias in join_list:
|
self.promote_joins(join_list, True)
|
||||||
self.promote_alias(column_alias, unconditional=True)
|
|
||||||
|
|
||||||
col = (join_list[-1], col)
|
col = (join_list[-1], col)
|
||||||
else:
|
else:
|
||||||
|
@ -1124,7 +1128,7 @@ class Query(object):
|
||||||
# If the comparison is against NULL, we may need to use some left
|
# If the comparison is against NULL, we may need to use some left
|
||||||
# outer joins when creating the join chain. This is only done when
|
# outer joins when creating the join chain. This is only done when
|
||||||
# needed, as it's less efficient at the database level.
|
# needed, as it's less efficient at the database level.
|
||||||
self.promote_alias_chain(join_list)
|
self.promote_joins(join_list)
|
||||||
join_promote = True
|
join_promote = True
|
||||||
|
|
||||||
# Process the join list to see if we can remove any inner joins from
|
# Process the join list to see if we can remove any inner joins from
|
||||||
|
@ -1155,16 +1159,16 @@ class Query(object):
|
||||||
# This means that we are dealing with two different query
|
# This means that we are dealing with two different query
|
||||||
# subtrees, so we don't need to do any join promotion.
|
# subtrees, so we don't need to do any join promotion.
|
||||||
continue
|
continue
|
||||||
join_promote = join_promote or self.promote_alias(join, unconditional)
|
join_promote = join_promote or self.promote_joins([join], unconditional)
|
||||||
if table != join:
|
if table != join:
|
||||||
table_promote = self.promote_alias(table)
|
table_promote = self.promote_joins([table])
|
||||||
# We only get here if we have found a table that exists
|
# We only get here if we have found a table that exists
|
||||||
# in the join list, but isn't on the original tables list.
|
# in the join list, but isn't on the original tables list.
|
||||||
# This means we've reached the point where we only have
|
# This means we've reached the point where we only have
|
||||||
# new tables, so we can break out of this promotion loop.
|
# new tables, so we can break out of this promotion loop.
|
||||||
break
|
break
|
||||||
self.promote_alias_chain(join_it, join_promote)
|
self.promote_joins(join_it, join_promote)
|
||||||
self.promote_alias_chain(table_it, table_promote or join_promote)
|
self.promote_joins(table_it, table_promote or join_promote)
|
||||||
|
|
||||||
if having_clause or force_having:
|
if having_clause or force_having:
|
||||||
if (alias, col) not in self.group_by:
|
if (alias, col) not in self.group_by:
|
||||||
|
@ -1176,7 +1180,7 @@ class Query(object):
|
||||||
connector)
|
connector)
|
||||||
|
|
||||||
if negate:
|
if negate:
|
||||||
self.promote_alias_chain(join_list)
|
self.promote_joins(join_list)
|
||||||
if lookup_type != 'isnull':
|
if lookup_type != 'isnull':
|
||||||
if len(join_list) > 1:
|
if len(join_list) > 1:
|
||||||
for alias in join_list:
|
for alias in join_list:
|
||||||
|
@ -1650,7 +1654,7 @@ class Query(object):
|
||||||
final_alias = join.lhs_alias
|
final_alias = join.lhs_alias
|
||||||
col = join.lhs_join_col
|
col = join.lhs_join_col
|
||||||
joins = joins[:-1]
|
joins = joins[:-1]
|
||||||
self.promote_alias_chain(joins[1:])
|
self.promote_joins(joins[1:])
|
||||||
self.select.append((final_alias, col))
|
self.select.append((final_alias, col))
|
||||||
self.select_fields.append(field)
|
self.select_fields.append(field)
|
||||||
except MultiJoin:
|
except MultiJoin:
|
||||||
|
|
|
@ -71,7 +71,8 @@ class BaseFormSet(object):
|
||||||
return True
|
return True
|
||||||
__nonzero__ = __bool__ # Python 2
|
__nonzero__ = __bool__ # Python 2
|
||||||
|
|
||||||
def _management_form(self):
|
@property
|
||||||
|
def management_form(self):
|
||||||
"""Returns the ManagementForm instance for this FormSet."""
|
"""Returns the ManagementForm instance for this FormSet."""
|
||||||
if self.is_bound:
|
if self.is_bound:
|
||||||
form = ManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix)
|
form = ManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix)
|
||||||
|
@ -84,7 +85,6 @@ class BaseFormSet(object):
|
||||||
MAX_NUM_FORM_COUNT: self.max_num
|
MAX_NUM_FORM_COUNT: self.max_num
|
||||||
})
|
})
|
||||||
return form
|
return form
|
||||||
management_form = property(_management_form)
|
|
||||||
|
|
||||||
def total_form_count(self):
|
def total_form_count(self):
|
||||||
"""Returns the total number of forms in this FormSet."""
|
"""Returns the total number of forms in this FormSet."""
|
||||||
|
@ -140,17 +140,18 @@ class BaseFormSet(object):
|
||||||
self.add_fields(form, i)
|
self.add_fields(form, i)
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def _get_initial_forms(self):
|
@property
|
||||||
|
def initial_forms(self):
|
||||||
"""Return a list of all the initial forms in this formset."""
|
"""Return a list of all the initial forms in this formset."""
|
||||||
return self.forms[:self.initial_form_count()]
|
return self.forms[:self.initial_form_count()]
|
||||||
initial_forms = property(_get_initial_forms)
|
|
||||||
|
|
||||||
def _get_extra_forms(self):
|
@property
|
||||||
|
def extra_forms(self):
|
||||||
"""Return a list of all the extra forms in this formset."""
|
"""Return a list of all the extra forms in this formset."""
|
||||||
return self.forms[self.initial_form_count():]
|
return self.forms[self.initial_form_count():]
|
||||||
extra_forms = property(_get_extra_forms)
|
|
||||||
|
|
||||||
def _get_empty_form(self, **kwargs):
|
@property
|
||||||
|
def empty_form(self, **kwargs):
|
||||||
defaults = {
|
defaults = {
|
||||||
'auto_id': self.auto_id,
|
'auto_id': self.auto_id,
|
||||||
'prefix': self.add_prefix('__prefix__'),
|
'prefix': self.add_prefix('__prefix__'),
|
||||||
|
@ -160,19 +161,19 @@ class BaseFormSet(object):
|
||||||
form = self.form(**defaults)
|
form = self.form(**defaults)
|
||||||
self.add_fields(form, None)
|
self.add_fields(form, None)
|
||||||
return form
|
return form
|
||||||
empty_form = property(_get_empty_form)
|
|
||||||
|
|
||||||
# Maybe this should just go away?
|
# Maybe this should just go away?
|
||||||
def _get_cleaned_data(self):
|
@property
|
||||||
|
def cleaned_data(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of form.cleaned_data dicts for every form in self.forms.
|
Returns a list of form.cleaned_data dicts for every form in self.forms.
|
||||||
"""
|
"""
|
||||||
if not self.is_valid():
|
if not self.is_valid():
|
||||||
raise AttributeError("'%s' object has no attribute 'cleaned_data'" % self.__class__.__name__)
|
raise AttributeError("'%s' object has no attribute 'cleaned_data'" % self.__class__.__name__)
|
||||||
return [form.cleaned_data for form in self.forms]
|
return [form.cleaned_data for form in self.forms]
|
||||||
cleaned_data = property(_get_cleaned_data)
|
|
||||||
|
|
||||||
def _get_deleted_forms(self):
|
@property
|
||||||
|
def deleted_forms(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of forms that have been marked for deletion. Raises an
|
Returns a list of forms that have been marked for deletion. Raises an
|
||||||
AttributeError if deletion is not allowed.
|
AttributeError if deletion is not allowed.
|
||||||
|
@ -191,9 +192,9 @@ class BaseFormSet(object):
|
||||||
if self._should_delete_form(form):
|
if self._should_delete_form(form):
|
||||||
self._deleted_form_indexes.append(i)
|
self._deleted_form_indexes.append(i)
|
||||||
return [self.forms[i] for i in self._deleted_form_indexes]
|
return [self.forms[i] for i in self._deleted_form_indexes]
|
||||||
deleted_forms = property(_get_deleted_forms)
|
|
||||||
|
|
||||||
def _get_ordered_forms(self):
|
@property
|
||||||
|
def ordered_forms(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of form in the order specified by the incoming data.
|
Returns a list of form in the order specified by the incoming data.
|
||||||
Raises an AttributeError if ordering is not allowed.
|
Raises an AttributeError if ordering is not allowed.
|
||||||
|
@ -228,7 +229,6 @@ class BaseFormSet(object):
|
||||||
# Return a list of form.cleaned_data dicts in the order specified by
|
# Return a list of form.cleaned_data dicts in the order specified by
|
||||||
# the form data.
|
# the form data.
|
||||||
return [self.forms[i[0]] for i in self._ordering]
|
return [self.forms[i[0]] for i in self._ordering]
|
||||||
ordered_forms = property(_get_ordered_forms)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_default_prefix(cls):
|
def get_default_prefix(cls):
|
||||||
|
@ -244,23 +244,20 @@ class BaseFormSet(object):
|
||||||
return self._non_form_errors
|
return self._non_form_errors
|
||||||
return self.error_class()
|
return self.error_class()
|
||||||
|
|
||||||
def _get_errors(self):
|
@property
|
||||||
|
def errors(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of form.errors for every form in self.forms.
|
Returns a list of form.errors for every form in self.forms.
|
||||||
"""
|
"""
|
||||||
if self._errors is None:
|
if self._errors is None:
|
||||||
self.full_clean()
|
self.full_clean()
|
||||||
return self._errors
|
return self._errors
|
||||||
errors = property(_get_errors)
|
|
||||||
|
|
||||||
def _should_delete_form(self, form):
|
def _should_delete_form(self, form):
|
||||||
# The way we lookup the value of the deletion field here takes
|
"""
|
||||||
# more code than we'd like, but the form's cleaned_data will
|
Returns whether or not the form was marked for deletion.
|
||||||
# not exist if the form is invalid.
|
"""
|
||||||
field = form.fields[DELETION_FIELD_NAME]
|
return form.cleaned_data.get(DELETION_FIELD_NAME, False)
|
||||||
raw_value = form._raw_value(DELETION_FIELD_NAME)
|
|
||||||
should_delete = field.clean(raw_value)
|
|
||||||
return should_delete
|
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"""
|
"""
|
||||||
|
@ -335,14 +332,14 @@ class BaseFormSet(object):
|
||||||
"""
|
"""
|
||||||
return self.forms and self.forms[0].is_multipart()
|
return self.forms and self.forms[0].is_multipart()
|
||||||
|
|
||||||
def _get_media(self):
|
@property
|
||||||
|
def media(self):
|
||||||
# All the forms on a FormSet are the same, so you only need to
|
# All the forms on a FormSet are the same, so you only need to
|
||||||
# interrogate the first form for media.
|
# interrogate the first form for media.
|
||||||
if self.forms:
|
if self.forms:
|
||||||
return self.forms[0].media
|
return self.forms[0].media
|
||||||
else:
|
else:
|
||||||
return Media()
|
return Media()
|
||||||
media = property(_get_media)
|
|
||||||
|
|
||||||
def as_table(self):
|
def as_table(self):
|
||||||
"Returns this formset rendered as HTML <tr>s -- excluding the <table></table>."
|
"Returns this formset rendered as HTML <tr>s -- excluding the <table></table>."
|
||||||
|
|
|
@ -18,7 +18,6 @@ from django.utils.datastructures import SortedDict
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.text import get_text_list, capfirst
|
from django.utils.text import get_text_list, capfirst
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
@ -592,6 +591,10 @@ class BaseModelFormSet(BaseFormSet):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
saved_instances = []
|
saved_instances = []
|
||||||
|
try:
|
||||||
|
forms_to_delete = self.deleted_forms
|
||||||
|
except AttributeError:
|
||||||
|
forms_to_delete = []
|
||||||
for form in self.initial_forms:
|
for form in self.initial_forms:
|
||||||
pk_name = self._pk_field.name
|
pk_name = self._pk_field.name
|
||||||
raw_pk_value = form._raw_value(pk_name)
|
raw_pk_value = form._raw_value(pk_name)
|
||||||
|
@ -602,7 +605,7 @@ class BaseModelFormSet(BaseFormSet):
|
||||||
pk_value = getattr(pk_value, 'pk', pk_value)
|
pk_value = getattr(pk_value, 'pk', pk_value)
|
||||||
|
|
||||||
obj = self._existing_object(pk_value)
|
obj = self._existing_object(pk_value)
|
||||||
if self.can_delete and self._should_delete_form(form):
|
if form in forms_to_delete:
|
||||||
self.deleted_objects.append(obj)
|
self.deleted_objects.append(obj)
|
||||||
obj.delete()
|
obj.delete()
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -61,14 +61,14 @@ else:
|
||||||
if not _cookie_allows_colon_in_names:
|
if not _cookie_allows_colon_in_names:
|
||||||
def load(self, rawdata):
|
def load(self, rawdata):
|
||||||
self.bad_cookies = set()
|
self.bad_cookies = set()
|
||||||
super(SimpleCookie, self).load(smart_str(rawdata))
|
super(SimpleCookie, self).load(force_str(rawdata))
|
||||||
for key in self.bad_cookies:
|
for key in self.bad_cookies:
|
||||||
del self[key]
|
del self[key]
|
||||||
|
|
||||||
# override private __set() method:
|
# override private __set() method:
|
||||||
# (needed for using our Morsel, and for laxness with CookieError
|
# (needed for using our Morsel, and for laxness with CookieError
|
||||||
def _BaseCookie__set(self, key, real_value, coded_value):
|
def _BaseCookie__set(self, key, real_value, coded_value):
|
||||||
key = smart_str(key)
|
key = force_str(key)
|
||||||
try:
|
try:
|
||||||
M = self.get(key, Morsel())
|
M = self.get(key, Morsel())
|
||||||
M.set(key, real_value, coded_value)
|
M.set(key, real_value, coded_value)
|
||||||
|
@ -85,7 +85,7 @@ from django.core.files import uploadhandler
|
||||||
from django.http.multipartparser import MultiPartParser
|
from django.http.multipartparser import MultiPartParser
|
||||||
from django.http.utils import *
|
from django.http.utils import *
|
||||||
from django.utils.datastructures import MultiValueDict, ImmutableList
|
from django.utils.datastructures import MultiValueDict, ImmutableList
|
||||||
from django.utils.encoding import smart_bytes, smart_str, iri_to_uri, force_text
|
from django.utils.encoding import force_bytes, force_str, force_text, iri_to_uri
|
||||||
from django.utils.http import cookie_date
|
from django.utils.http import cookie_date
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -137,7 +137,7 @@ def build_request_repr(request, path_override=None, GET_override=None,
|
||||||
except Exception:
|
except Exception:
|
||||||
meta = '<could not parse>'
|
meta = '<could not parse>'
|
||||||
path = path_override if path_override is not None else request.path
|
path = path_override if path_override is not None else request.path
|
||||||
return smart_str('<%s\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' %
|
return force_str('<%s\npath:%s,\nGET:%s,\nPOST:%s,\nCOOKIES:%s,\nMETA:%s>' %
|
||||||
(request.__class__.__name__,
|
(request.__class__.__name__,
|
||||||
path,
|
path,
|
||||||
six.text_type(get),
|
six.text_type(get),
|
||||||
|
@ -243,7 +243,12 @@ class HttpRequest(object):
|
||||||
def is_ajax(self):
|
def is_ajax(self):
|
||||||
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
|
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
|
||||||
|
|
||||||
def _set_encoding(self, val):
|
@property
|
||||||
|
def encoding(self):
|
||||||
|
return self._encoding
|
||||||
|
|
||||||
|
@encoding.setter
|
||||||
|
def encoding(self, val):
|
||||||
"""
|
"""
|
||||||
Sets the encoding used for GET/POST accesses. If the GET or POST
|
Sets the encoding used for GET/POST accesses. If the GET or POST
|
||||||
dictionary has already been created, it is removed and recreated on the
|
dictionary has already been created, it is removed and recreated on the
|
||||||
|
@ -255,27 +260,22 @@ class HttpRequest(object):
|
||||||
if hasattr(self, '_post'):
|
if hasattr(self, '_post'):
|
||||||
del self._post
|
del self._post
|
||||||
|
|
||||||
def _get_encoding(self):
|
|
||||||
return self._encoding
|
|
||||||
|
|
||||||
encoding = property(_get_encoding, _set_encoding)
|
|
||||||
|
|
||||||
def _initialize_handlers(self):
|
def _initialize_handlers(self):
|
||||||
self._upload_handlers = [uploadhandler.load_handler(handler, self)
|
self._upload_handlers = [uploadhandler.load_handler(handler, self)
|
||||||
for handler in settings.FILE_UPLOAD_HANDLERS]
|
for handler in settings.FILE_UPLOAD_HANDLERS]
|
||||||
|
|
||||||
def _set_upload_handlers(self, upload_handlers):
|
@property
|
||||||
if hasattr(self, '_files'):
|
def upload_handlers(self):
|
||||||
raise AttributeError("You cannot set the upload handlers after the upload has been processed.")
|
|
||||||
self._upload_handlers = upload_handlers
|
|
||||||
|
|
||||||
def _get_upload_handlers(self):
|
|
||||||
if not self._upload_handlers:
|
if not self._upload_handlers:
|
||||||
# If there are no upload handlers defined, initialize them from settings.
|
# If there are no upload handlers defined, initialize them from settings.
|
||||||
self._initialize_handlers()
|
self._initialize_handlers()
|
||||||
return self._upload_handlers
|
return self._upload_handlers
|
||||||
|
|
||||||
upload_handlers = property(_get_upload_handlers, _set_upload_handlers)
|
@upload_handlers.setter
|
||||||
|
def upload_handlers(self, upload_handlers):
|
||||||
|
if hasattr(self, '_files'):
|
||||||
|
raise AttributeError("You cannot set the upload handlers after the upload has been processed.")
|
||||||
|
self._upload_handlers = upload_handlers
|
||||||
|
|
||||||
def parse_file_upload(self, META, post_data):
|
def parse_file_upload(self, META, post_data):
|
||||||
"""Returns a tuple of (POST QueryDict, FILES MultiValueDict)."""
|
"""Returns a tuple of (POST QueryDict, FILES MultiValueDict)."""
|
||||||
|
@ -397,16 +397,16 @@ class QueryDict(MultiValueDict):
|
||||||
force_text(value, encoding, errors='replace'))
|
force_text(value, encoding, errors='replace'))
|
||||||
self._mutable = mutable
|
self._mutable = mutable
|
||||||
|
|
||||||
def _get_encoding(self):
|
@property
|
||||||
|
def encoding(self):
|
||||||
if self._encoding is None:
|
if self._encoding is None:
|
||||||
self._encoding = settings.DEFAULT_CHARSET
|
self._encoding = settings.DEFAULT_CHARSET
|
||||||
return self._encoding
|
return self._encoding
|
||||||
|
|
||||||
def _set_encoding(self, value):
|
@encoding.setter
|
||||||
|
def encoding(self, value):
|
||||||
self._encoding = value
|
self._encoding = value
|
||||||
|
|
||||||
encoding = property(_get_encoding, _set_encoding)
|
|
||||||
|
|
||||||
def _assert_mutable(self):
|
def _assert_mutable(self):
|
||||||
if not self._mutable:
|
if not self._mutable:
|
||||||
raise AttributeError("This QueryDict instance is immutable")
|
raise AttributeError("This QueryDict instance is immutable")
|
||||||
|
@ -489,13 +489,13 @@ class QueryDict(MultiValueDict):
|
||||||
"""
|
"""
|
||||||
output = []
|
output = []
|
||||||
if safe:
|
if safe:
|
||||||
safe = smart_bytes(safe, self.encoding)
|
safe = force_bytes(safe, self.encoding)
|
||||||
encode = lambda k, v: '%s=%s' % ((quote(k, safe), quote(v, safe)))
|
encode = lambda k, v: '%s=%s' % ((quote(k, safe), quote(v, safe)))
|
||||||
else:
|
else:
|
||||||
encode = lambda k, v: urlencode({k: v})
|
encode = lambda k, v: urlencode({k: v})
|
||||||
for k, list_ in self.lists():
|
for k, list_ in self.lists():
|
||||||
k = smart_bytes(k, self.encoding)
|
k = force_bytes(k, self.encoding)
|
||||||
output.extend([encode(k, smart_bytes(v, self.encoding))
|
output.extend([encode(k, force_bytes(v, self.encoding))
|
||||||
for v in list_])
|
for v in list_])
|
||||||
return '&'.join(output)
|
return '&'.join(output)
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ class HttpResponse(object):
|
||||||
if not content_type:
|
if not content_type:
|
||||||
content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
|
content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
|
||||||
self._charset)
|
self._charset)
|
||||||
# content is a bytestring. See _get_content / _set_content.
|
# content is a bytestring. See the content property methods.
|
||||||
self.content = content
|
self.content = content
|
||||||
self.cookies = SimpleCookie()
|
self.cookies = SimpleCookie()
|
||||||
if status:
|
if status:
|
||||||
|
@ -669,7 +669,8 @@ class HttpResponse(object):
|
||||||
self.set_cookie(key, max_age=0, path=path, domain=domain,
|
self.set_cookie(key, max_age=0, path=path, domain=domain,
|
||||||
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
expires='Thu, 01-Jan-1970 00:00:00 GMT')
|
||||||
|
|
||||||
def _get_content(self):
|
@property
|
||||||
|
def content(self):
|
||||||
if self.has_header('Content-Encoding'):
|
if self.has_header('Content-Encoding'):
|
||||||
def make_bytes(value):
|
def make_bytes(value):
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
|
@ -679,9 +680,10 @@ class HttpResponse(object):
|
||||||
# force conversion to bytes in case chunk is a subclass
|
# force conversion to bytes in case chunk is a subclass
|
||||||
return bytes(value)
|
return bytes(value)
|
||||||
return b''.join(make_bytes(e) for e in self._container)
|
return b''.join(make_bytes(e) for e in self._container)
|
||||||
return b''.join(smart_bytes(e, self._charset) for e in self._container)
|
return b''.join(force_bytes(e, self._charset) for e in self._container)
|
||||||
|
|
||||||
def _set_content(self, value):
|
@content.setter
|
||||||
|
def content(self, value):
|
||||||
if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
|
if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
|
||||||
self._container = value
|
self._container = value
|
||||||
self._base_content_is_iter = True
|
self._base_content_is_iter = True
|
||||||
|
@ -689,8 +691,6 @@ class HttpResponse(object):
|
||||||
self._container = [value]
|
self._container = [value]
|
||||||
self._base_content_is_iter = False
|
self._base_content_is_iter = False
|
||||||
|
|
||||||
content = property(_get_content, _set_content)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
self._iterator = iter(self._container)
|
self._iterator = iter(self._container)
|
||||||
return self
|
return self
|
||||||
|
@ -728,11 +728,11 @@ class HttpResponse(object):
|
||||||
class HttpResponseRedirectBase(HttpResponse):
|
class HttpResponseRedirectBase(HttpResponse):
|
||||||
allowed_schemes = ['http', 'https', 'ftp']
|
allowed_schemes = ['http', 'https', 'ftp']
|
||||||
|
|
||||||
def __init__(self, redirect_to):
|
def __init__(self, redirect_to, *args, **kwargs):
|
||||||
parsed = urlparse(redirect_to)
|
parsed = urlparse(redirect_to)
|
||||||
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
|
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
|
||||||
raise SuspiciousOperation("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
|
raise SuspiciousOperation("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
|
||||||
super(HttpResponseRedirectBase, self).__init__()
|
super(HttpResponseRedirectBase, self).__init__(*args, **kwargs)
|
||||||
self['Location'] = iri_to_uri(redirect_to)
|
self['Location'] = iri_to_uri(redirect_to)
|
||||||
|
|
||||||
class HttpResponseRedirect(HttpResponseRedirectBase):
|
class HttpResponseRedirect(HttpResponseRedirectBase):
|
||||||
|
@ -744,6 +744,16 @@ class HttpResponsePermanentRedirect(HttpResponseRedirectBase):
|
||||||
class HttpResponseNotModified(HttpResponse):
|
class HttpResponseNotModified(HttpResponse):
|
||||||
status_code = 304
|
status_code = 304
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(HttpResponseNotModified, self).__init__(*args, **kwargs)
|
||||||
|
del self['content-type']
|
||||||
|
|
||||||
|
@HttpResponse.content.setter
|
||||||
|
def content(self, value):
|
||||||
|
if value:
|
||||||
|
raise AttributeError("You cannot set content to a 304 (Not Modified) response")
|
||||||
|
self._container = []
|
||||||
|
|
||||||
class HttpResponseBadRequest(HttpResponse):
|
class HttpResponseBadRequest(HttpResponse):
|
||||||
status_code = 400
|
status_code = 400
|
||||||
|
|
||||||
|
@ -756,8 +766,8 @@ class HttpResponseForbidden(HttpResponse):
|
||||||
class HttpResponseNotAllowed(HttpResponse):
|
class HttpResponseNotAllowed(HttpResponse):
|
||||||
status_code = 405
|
status_code = 405
|
||||||
|
|
||||||
def __init__(self, permitted_methods):
|
def __init__(self, permitted_methods, *args, **kwargs):
|
||||||
super(HttpResponseNotAllowed, self).__init__()
|
super(HttpResponseNotAllowed, self).__init__(*args, **kwargs)
|
||||||
self['Allow'] = ', '.join(permitted_methods)
|
self['Allow'] = ', '.join(permitted_methods)
|
||||||
|
|
||||||
class HttpResponseGone(HttpResponse):
|
class HttpResponseGone(HttpResponse):
|
||||||
|
|
|
@ -11,7 +11,7 @@ from django.utils.importlib import import_module
|
||||||
from django.utils.itercompat import is_iterable
|
from django.utils.itercompat import is_iterable
|
||||||
from django.utils.text import (smart_split, unescape_string_literal,
|
from django.utils.text import (smart_split, unescape_string_literal,
|
||||||
get_text_list)
|
get_text_list)
|
||||||
from django.utils.encoding import smart_text, force_text, smart_str
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.translation import ugettext_lazy, pgettext_lazy
|
from django.utils.translation import ugettext_lazy, pgettext_lazy
|
||||||
from django.utils.safestring import (SafeData, EscapeData, mark_safe,
|
from django.utils.safestring import (SafeData, EscapeData, mark_safe,
|
||||||
mark_for_escaping)
|
mark_for_escaping)
|
||||||
|
@ -116,7 +116,7 @@ class Template(object):
|
||||||
def __init__(self, template_string, origin=None,
|
def __init__(self, template_string, origin=None,
|
||||||
name='<Unknown Template>'):
|
name='<Unknown Template>'):
|
||||||
try:
|
try:
|
||||||
template_string = smart_text(template_string)
|
template_string = force_text(template_string)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
raise TemplateEncodingError("Templates can only be constructed "
|
raise TemplateEncodingError("Templates can only be constructed "
|
||||||
"from unicode or UTF-8 strings.")
|
"from unicode or UTF-8 strings.")
|
||||||
|
@ -848,7 +848,7 @@ class TextNode(Node):
|
||||||
self.s = s
|
self.s = s
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Text Node: '%s'>" % smart_str(self.s[:25], 'ascii',
|
return force_str("<Text Node: '%s'>" % self.s[:25], 'ascii',
|
||||||
errors='replace')
|
errors='replace')
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
|
|
|
@ -102,7 +102,7 @@ class SimpleTemplateResponse(HttpResponse):
|
||||||
"""
|
"""
|
||||||
retval = self
|
retval = self
|
||||||
if not self._is_rendered:
|
if not self._is_rendered:
|
||||||
self._set_content(self.rendered_content)
|
self.content = self.rendered_content
|
||||||
for post_callback in self._post_render_callbacks:
|
for post_callback in self._post_render_callbacks:
|
||||||
newretval = post_callback(retval)
|
newretval = post_callback(retval)
|
||||||
if newretval is not None:
|
if newretval is not None:
|
||||||
|
@ -119,20 +119,20 @@ class SimpleTemplateResponse(HttpResponse):
|
||||||
'rendered before it can be iterated over.')
|
'rendered before it can be iterated over.')
|
||||||
return super(SimpleTemplateResponse, self).__iter__()
|
return super(SimpleTemplateResponse, self).__iter__()
|
||||||
|
|
||||||
def _get_content(self):
|
@property
|
||||||
|
def content(self):
|
||||||
if not self._is_rendered:
|
if not self._is_rendered:
|
||||||
raise ContentNotRenderedError('The response content must be '
|
raise ContentNotRenderedError('The response content must be '
|
||||||
'rendered before it can be accessed.')
|
'rendered before it can be accessed.')
|
||||||
return super(SimpleTemplateResponse, self)._get_content()
|
return super(SimpleTemplateResponse, self).content
|
||||||
|
|
||||||
def _set_content(self, value):
|
@content.setter
|
||||||
|
def content(self, value):
|
||||||
"""Sets the content for the response
|
"""Sets the content for the response
|
||||||
"""
|
"""
|
||||||
super(SimpleTemplateResponse, self)._set_content(value)
|
HttpResponse.content.fset(self, value)
|
||||||
self._is_rendered = True
|
self._is_rendered = True
|
||||||
|
|
||||||
content = property(_get_content, _set_content)
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateResponse(SimpleTemplateResponse):
|
class TemplateResponse(SimpleTemplateResponse):
|
||||||
rendering_attrs = SimpleTemplateResponse.rendering_attrs + \
|
rendering_attrs = SimpleTemplateResponse.rendering_attrs + \
|
||||||
|
|
|
@ -4,7 +4,7 @@ import hashlib
|
||||||
from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist
|
from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist
|
||||||
from django.template import resolve_variable
|
from django.template import resolve_variable
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
@ -26,8 +26,8 @@ class CacheNode(Node):
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
|
||||||
# Build a key for this fragment and all vary-on's.
|
# Build a key for this fragment and all vary-on's.
|
||||||
key = smart_bytes(':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on]))
|
key = ':'.join([urlquote(resolve_variable(var, context)) for var in self.vary_on])
|
||||||
args = hashlib.md5(key)
|
args = hashlib.md5(force_bytes(key))
|
||||||
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
|
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
|
||||||
value = cache.get(cache_key)
|
value = cache.get(cache_key)
|
||||||
if value is None:
|
if value is None:
|
||||||
|
|
|
@ -21,7 +21,7 @@ from django.http import SimpleCookie, HttpRequest, QueryDict
|
||||||
from django.template import TemplateDoesNotExist
|
from django.template import TemplateDoesNotExist
|
||||||
from django.test import signals
|
from django.test import signals
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.itercompat import is_iterable
|
from django.utils.itercompat import is_iterable
|
||||||
|
@ -110,7 +110,7 @@ def encode_multipart(boundary, data):
|
||||||
as an application/octet-stream; otherwise, str(value) will be sent.
|
as an application/octet-stream; otherwise, str(value) will be sent.
|
||||||
"""
|
"""
|
||||||
lines = []
|
lines = []
|
||||||
to_bytes = lambda s: smart_bytes(s, settings.DEFAULT_CHARSET)
|
to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
|
||||||
|
|
||||||
# Not by any means perfect, but good enough for our purposes.
|
# Not by any means perfect, but good enough for our purposes.
|
||||||
is_file = lambda thing: hasattr(thing, "read") and callable(thing.read)
|
is_file = lambda thing: hasattr(thing, "read") and callable(thing.read)
|
||||||
|
@ -147,7 +147,7 @@ def encode_multipart(boundary, data):
|
||||||
return b'\r\n'.join(lines)
|
return b'\r\n'.join(lines)
|
||||||
|
|
||||||
def encode_file(boundary, key, file):
|
def encode_file(boundary, key, file):
|
||||||
to_bytes = lambda s: smart_bytes(s, settings.DEFAULT_CHARSET)
|
to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
|
||||||
content_type = mimetypes.guess_type(file.name)[0]
|
content_type = mimetypes.guess_type(file.name)[0]
|
||||||
if content_type is None:
|
if content_type is None:
|
||||||
content_type = 'application/octet-stream'
|
content_type = 'application/octet-stream'
|
||||||
|
@ -222,7 +222,7 @@ class RequestFactory(object):
|
||||||
charset = match.group(1)
|
charset = match.group(1)
|
||||||
else:
|
else:
|
||||||
charset = settings.DEFAULT_CHARSET
|
charset = settings.DEFAULT_CHARSET
|
||||||
return smart_bytes(data, encoding=charset)
|
return force_bytes(data, encoding=charset)
|
||||||
|
|
||||||
def _get_path(self, parsed):
|
def _get_path(self, parsed):
|
||||||
# If there are parameters, add them
|
# If there are parameters, add them
|
||||||
|
@ -293,7 +293,7 @@ class RequestFactory(object):
|
||||||
def generic(self, method, path,
|
def generic(self, method, path,
|
||||||
data='', content_type='application/octet-stream', **extra):
|
data='', content_type='application/octet-stream', **extra):
|
||||||
parsed = urlparse(path)
|
parsed = urlparse(path)
|
||||||
data = smart_bytes(data, settings.DEFAULT_CHARSET)
|
data = force_bytes(data, settings.DEFAULT_CHARSET)
|
||||||
r = {
|
r = {
|
||||||
'PATH_INFO': self._get_path(parsed),
|
'PATH_INFO': self._get_path(parsed),
|
||||||
'QUERY_STRING': parsed[4],
|
'QUERY_STRING': parsed[4],
|
||||||
|
|
|
@ -4,7 +4,6 @@ import time
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
from django.dispatch import receiver, Signal
|
from django.dispatch import receiver, Signal
|
||||||
from django.template import context
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
template_rendered = Signal(providing_args=["template", "context"])
|
template_rendered = Signal(providing_args=["template", "context"])
|
||||||
|
@ -48,9 +47,17 @@ def update_connections_time_zone(**kwargs):
|
||||||
@receiver(setting_changed)
|
@receiver(setting_changed)
|
||||||
def clear_context_processors_cache(**kwargs):
|
def clear_context_processors_cache(**kwargs):
|
||||||
if kwargs['setting'] == 'TEMPLATE_CONTEXT_PROCESSORS':
|
if kwargs['setting'] == 'TEMPLATE_CONTEXT_PROCESSORS':
|
||||||
|
from django.template import context
|
||||||
context._standard_context_processors = None
|
context._standard_context_processors = None
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(setting_changed)
|
||||||
|
def clear_serializers_cache(**kwargs):
|
||||||
|
if kwargs['setting'] == 'SERIALIZATION_MODULES':
|
||||||
|
from django.core import serializers
|
||||||
|
serializers._serializers = {}
|
||||||
|
|
||||||
|
|
||||||
@receiver(setting_changed)
|
@receiver(setting_changed)
|
||||||
def language_changed(**kwargs):
|
def language_changed(**kwargs):
|
||||||
if kwargs['setting'] in ('LOCALE_PATHS', 'LANGUAGE_CODE'):
|
if kwargs['setting'] in ('LOCALE_PATHS', 'LANGUAGE_CODE'):
|
||||||
|
|
|
@ -41,7 +41,7 @@ from django.test.utils import (get_warnings_state, restore_warnings_state,
|
||||||
override_settings)
|
override_settings)
|
||||||
from django.test.utils import ContextList
|
from django.test.utils import ContextList
|
||||||
from django.utils import unittest as ut2
|
from django.utils import unittest as ut2
|
||||||
from django.utils.encoding import smart_bytes, force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.unittest.util import safe_repr
|
from django.utils.unittest.util import safe_repr
|
||||||
from django.views.static import serve
|
from django.views.static import serve
|
||||||
|
|
|
@ -24,7 +24,7 @@ import time
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import get_cache
|
from django.core.cache import get_cache
|
||||||
from django.utils.encoding import iri_to_uri, force_text, smart_bytes
|
from django.utils.encoding import iri_to_uri, force_bytes, force_text
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
from django.utils.timezone import get_current_timezone_name
|
from django.utils.timezone import get_current_timezone_name
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
|
@ -181,14 +181,14 @@ def _generate_cache_key(request, method, headerlist, key_prefix):
|
||||||
value = request.META.get(header, None)
|
value = request.META.get(header, None)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
ctx.update(value)
|
ctx.update(value)
|
||||||
path = hashlib.md5(smart_bytes(iri_to_uri(request.get_full_path())))
|
path = hashlib.md5(force_bytes(iri_to_uri(request.get_full_path())))
|
||||||
cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
|
cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
|
||||||
key_prefix, method, path.hexdigest(), ctx.hexdigest())
|
key_prefix, method, path.hexdigest(), ctx.hexdigest())
|
||||||
return _i18n_cache_key_suffix(request, cache_key)
|
return _i18n_cache_key_suffix(request, cache_key)
|
||||||
|
|
||||||
def _generate_cache_header_key(key_prefix, request):
|
def _generate_cache_header_key(key_prefix, request):
|
||||||
"""Returns a cache key for the header cache."""
|
"""Returns a cache key for the header cache."""
|
||||||
path = hashlib.md5(smart_bytes(iri_to_uri(request.get_full_path())))
|
path = hashlib.md5(force_bytes(iri_to_uri(request.get_full_path())))
|
||||||
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
||||||
key_prefix, path.hexdigest())
|
key_prefix, path.hexdigest())
|
||||||
return _i18n_cache_key_suffix(request, cache_key)
|
return _i18n_cache_key_suffix(request, cache_key)
|
||||||
|
|
|
@ -23,7 +23,8 @@ except NotImplementedError:
|
||||||
using_sysrandom = False
|
using_sysrandom = False
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils.encoding import force_bytes
|
||||||
|
from django.utils import six
|
||||||
from django.utils.six.moves import xrange
|
from django.utils.six.moves import xrange
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ def salted_hmac(key_salt, value, secret=None):
|
||||||
# line is redundant and could be replaced by key = key_salt + secret, since
|
# line is redundant and could be replaced by key = key_salt + secret, since
|
||||||
# the hmac module does the same thing for keys longer than the block size.
|
# the hmac module does the same thing for keys longer than the block size.
|
||||||
# However, we need to ensure that we *always* do this.
|
# However, we need to ensure that we *always* do this.
|
||||||
return hmac.new(key, msg=smart_bytes(value), digestmod=hashlib.sha1)
|
return hmac.new(key, msg=force_bytes(value), digestmod=hashlib.sha1)
|
||||||
|
|
||||||
|
|
||||||
def get_random_string(length=12,
|
def get_random_string(length=12,
|
||||||
|
@ -88,8 +89,12 @@ def constant_time_compare(val1, val2):
|
||||||
if len(val1) != len(val2):
|
if len(val1) != len(val2):
|
||||||
return False
|
return False
|
||||||
result = 0
|
result = 0
|
||||||
for x, y in zip(val1, val2):
|
if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
|
||||||
result |= ord(x) ^ ord(y)
|
for x, y in zip(val1, val2):
|
||||||
|
result |= x ^ y
|
||||||
|
else:
|
||||||
|
for x, y in zip(val1, val2):
|
||||||
|
result |= ord(x) ^ ord(y)
|
||||||
return result == 0
|
return result == 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,8 +147,8 @@ def pbkdf2(password, salt, iterations, dklen=0, digest=None):
|
||||||
assert iterations > 0
|
assert iterations > 0
|
||||||
if not digest:
|
if not digest:
|
||||||
digest = hashlib.sha256
|
digest = hashlib.sha256
|
||||||
password = smart_bytes(password)
|
password = force_bytes(password)
|
||||||
salt = smart_bytes(salt)
|
salt = force_bytes(salt)
|
||||||
hlen = digest().digest_size
|
hlen = digest().digest_size
|
||||||
if not dklen:
|
if not dklen:
|
||||||
dklen = hlen
|
dklen = hlen
|
||||||
|
|
|
@ -174,7 +174,7 @@ def force_bytes(s, encoding='utf-8', strings_only=False, errors='strict'):
|
||||||
# An Exception subclass containing non-ASCII data that doesn't
|
# An Exception subclass containing non-ASCII data that doesn't
|
||||||
# know how to print itself properly. We shouldn't raise a
|
# know how to print itself properly. We shouldn't raise a
|
||||||
# further exception.
|
# further exception.
|
||||||
return ' '.join([smart_bytes(arg, encoding, strings_only,
|
return b' '.join([force_bytes(arg, encoding, strings_only,
|
||||||
errors) for arg in s])
|
errors) for arg in s])
|
||||||
return six.text_type(s).encode(encoding, errors)
|
return six.text_type(s).encode(encoding, errors)
|
||||||
else:
|
else:
|
||||||
|
@ -225,7 +225,7 @@ def iri_to_uri(iri):
|
||||||
# converted.
|
# converted.
|
||||||
if iri is None:
|
if iri is None:
|
||||||
return iri
|
return iri
|
||||||
return quote(smart_bytes(iri), safe=b"/#%[]=:;$&()+,!?*@'~")
|
return quote(force_bytes(iri), safe=b"/#%[]=:;$&()+,!?*@'~")
|
||||||
|
|
||||||
def filepath_to_uri(path):
|
def filepath_to_uri(path):
|
||||||
"""Convert an file system path to a URI portion that is suitable for
|
"""Convert an file system path to a URI portion that is suitable for
|
||||||
|
@ -244,7 +244,7 @@ def filepath_to_uri(path):
|
||||||
return path
|
return path
|
||||||
# I know about `os.sep` and `os.altsep` but I want to leave
|
# I know about `os.sep` and `os.altsep` but I want to leave
|
||||||
# some flexibility for hardcoding separators.
|
# some flexibility for hardcoding separators.
|
||||||
return quote(smart_bytes(path.replace("\\", "/")), safe=b"/~!*()'")
|
return quote(force_bytes(path.replace("\\", "/")), safe=b"/~!*()'")
|
||||||
|
|
||||||
# The encoding of the default system locale but falls back to the
|
# The encoding of the default system locale but falls back to the
|
||||||
# given fallback encoding if the encoding is unsupported by python or could
|
# given fallback encoding if the encoding is unsupported by python or could
|
||||||
|
|
|
@ -4,7 +4,7 @@ import datetime
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import dateformat, numberformat, datetime_safe
|
from django.utils import dateformat, numberformat, datetime_safe
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -66,7 +66,7 @@ def get_format(format_type, lang=None, use_l10n=None):
|
||||||
If use_l10n is provided and is not None, that will force the value to
|
If use_l10n is provided and is not None, that will force the value to
|
||||||
be localized (or not), overriding the value of settings.USE_L10N.
|
be localized (or not), overriding the value of settings.USE_L10N.
|
||||||
"""
|
"""
|
||||||
format_type = smart_str(format_type)
|
format_type = force_str(format_type)
|
||||||
if use_l10n or (use_l10n is None and settings.USE_L10N):
|
if use_l10n or (use_l10n is None and settings.USE_L10N):
|
||||||
if lang is None:
|
if lang is None:
|
||||||
lang = get_language()
|
lang = get_language()
|
||||||
|
@ -160,14 +160,14 @@ def localize_input(value, default=None):
|
||||||
return number_format(value)
|
return number_format(value)
|
||||||
elif isinstance(value, datetime.datetime):
|
elif isinstance(value, datetime.datetime):
|
||||||
value = datetime_safe.new_datetime(value)
|
value = datetime_safe.new_datetime(value)
|
||||||
format = smart_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
|
format = force_str(default or get_format('DATETIME_INPUT_FORMATS')[0])
|
||||||
return value.strftime(format)
|
return value.strftime(format)
|
||||||
elif isinstance(value, datetime.date):
|
elif isinstance(value, datetime.date):
|
||||||
value = datetime_safe.new_date(value)
|
value = datetime_safe.new_date(value)
|
||||||
format = smart_str(default or get_format('DATE_INPUT_FORMATS')[0])
|
format = force_str(default or get_format('DATE_INPUT_FORMATS')[0])
|
||||||
return value.strftime(format)
|
return value.strftime(format)
|
||||||
elif isinstance(value, datetime.time):
|
elif isinstance(value, datetime.time):
|
||||||
format = smart_str(default or get_format('TIME_INPUT_FORMATS')[0])
|
format = force_str(default or get_format('TIME_INPUT_FORMATS')[0])
|
||||||
return value.strftime(format)
|
return value.strftime(format)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,6 @@ class LazyObject(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
# introspection support:
|
# introspection support:
|
||||||
__members__ = property(lambda self: self.__dir__())
|
|
||||||
__dir__ = new_method_proxy(dir)
|
__dir__ = new_method_proxy(dir)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ except ImportError: # Python 2
|
||||||
from urlparse import urlsplit, urlunsplit
|
from urlparse import urlsplit, urlunsplit
|
||||||
|
|
||||||
from django.utils.safestring import SafeData, mark_safe
|
from django.utils.safestring import SafeData, mark_safe
|
||||||
from django.utils.encoding import smart_bytes, force_text
|
from django.utils.encoding import force_bytes, force_text
|
||||||
from django.utils.functional import allow_lazy
|
from django.utils.functional import allow_lazy
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.text import normalize_newlines
|
from django.utils.text import normalize_newlines
|
||||||
|
@ -164,7 +164,7 @@ def smart_urlquote(url):
|
||||||
# contains a % not followed by two hexadecimal digits. See #9655.
|
# contains a % not followed by two hexadecimal digits. See #9655.
|
||||||
if '%' not in url or unquoted_percents_re.search(url):
|
if '%' not in url or unquoted_percents_re.search(url):
|
||||||
# See http://bugs.python.org/issue2637
|
# See http://bugs.python.org/issue2637
|
||||||
url = quote(smart_bytes(url), safe=b'!*\'();:@&=+$,/?#[]~')
|
url = quote(force_bytes(url), safe=b'!*\'();:@&=+$,/?#[]~')
|
||||||
|
|
||||||
return force_text(url)
|
return force_text(url)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ except ImportError: # Python 2
|
||||||
from email.utils import formatdate
|
from email.utils import formatdate
|
||||||
|
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.encoding import force_text, smart_str
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.functional import allow_lazy
|
from django.utils.functional import allow_lazy
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ def urlquote(url, safe='/'):
|
||||||
can safely be used as part of an argument to a subsequent iri_to_uri() call
|
can safely be used as part of an argument to a subsequent iri_to_uri() call
|
||||||
without double-quoting occurring.
|
without double-quoting occurring.
|
||||||
"""
|
"""
|
||||||
return force_text(urllib_parse.quote(smart_str(url), smart_str(safe)))
|
return force_text(urllib_parse.quote(force_str(url), force_str(safe)))
|
||||||
urlquote = allow_lazy(urlquote, six.text_type)
|
urlquote = allow_lazy(urlquote, six.text_type)
|
||||||
|
|
||||||
def urlquote_plus(url, safe=''):
|
def urlquote_plus(url, safe=''):
|
||||||
|
@ -49,7 +49,7 @@ def urlquote_plus(url, safe=''):
|
||||||
returned string can safely be used as part of an argument to a subsequent
|
returned string can safely be used as part of an argument to a subsequent
|
||||||
iri_to_uri() call without double-quoting occurring.
|
iri_to_uri() call without double-quoting occurring.
|
||||||
"""
|
"""
|
||||||
return force_text(urllib_parse.quote_plus(smart_str(url), smart_str(safe)))
|
return force_text(urllib_parse.quote_plus(force_str(url), force_str(safe)))
|
||||||
urlquote_plus = allow_lazy(urlquote_plus, six.text_type)
|
urlquote_plus = allow_lazy(urlquote_plus, six.text_type)
|
||||||
|
|
||||||
def urlunquote(quoted_url):
|
def urlunquote(quoted_url):
|
||||||
|
@ -57,7 +57,7 @@ def urlunquote(quoted_url):
|
||||||
A wrapper for Python's urllib.unquote() function that can operate on
|
A wrapper for Python's urllib.unquote() function that can operate on
|
||||||
the result of django.utils.http.urlquote().
|
the result of django.utils.http.urlquote().
|
||||||
"""
|
"""
|
||||||
return force_text(urllib_parse.unquote(smart_str(quoted_url)))
|
return force_text(urllib_parse.unquote(force_str(quoted_url)))
|
||||||
urlunquote = allow_lazy(urlunquote, six.text_type)
|
urlunquote = allow_lazy(urlunquote, six.text_type)
|
||||||
|
|
||||||
def urlunquote_plus(quoted_url):
|
def urlunquote_plus(quoted_url):
|
||||||
|
@ -65,7 +65,7 @@ def urlunquote_plus(quoted_url):
|
||||||
A wrapper for Python's urllib.unquote_plus() function that can operate on
|
A wrapper for Python's urllib.unquote_plus() function that can operate on
|
||||||
the result of django.utils.http.urlquote_plus().
|
the result of django.utils.http.urlquote_plus().
|
||||||
"""
|
"""
|
||||||
return force_text(urllib_parse.unquote_plus(smart_str(quoted_url)))
|
return force_text(urllib_parse.unquote_plus(force_str(quoted_url)))
|
||||||
urlunquote_plus = allow_lazy(urlunquote_plus, six.text_type)
|
urlunquote_plus = allow_lazy(urlunquote_plus, six.text_type)
|
||||||
|
|
||||||
def urlencode(query, doseq=0):
|
def urlencode(query, doseq=0):
|
||||||
|
@ -79,8 +79,8 @@ def urlencode(query, doseq=0):
|
||||||
elif hasattr(query, 'items'):
|
elif hasattr(query, 'items'):
|
||||||
query = query.items()
|
query = query.items()
|
||||||
return urllib_parse.urlencode(
|
return urllib_parse.urlencode(
|
||||||
[(smart_str(k),
|
[(force_str(k),
|
||||||
[smart_str(i) for i in v] if isinstance(v, (list,tuple)) else smart_str(v))
|
[force_str(i) for i in v] if isinstance(v, (list,tuple)) else force_str(v))
|
||||||
for k, v in query],
|
for k, v in query],
|
||||||
doseq)
|
doseq)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
|
|
||||||
|
|
||||||
# True if we are running on Python 3.
|
# True if we are running on Python 3.
|
||||||
|
@ -26,19 +26,23 @@ else:
|
||||||
text_type = unicode
|
text_type = unicode
|
||||||
binary_type = str
|
binary_type = str
|
||||||
|
|
||||||
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
if sys.platform == "java":
|
||||||
class X(object):
|
# Jython always uses 32 bits.
|
||||||
def __len__(self):
|
|
||||||
return 1 << 31
|
|
||||||
try:
|
|
||||||
len(X())
|
|
||||||
except OverflowError:
|
|
||||||
# 32-bit
|
|
||||||
MAXSIZE = int((1 << 31) - 1)
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
else:
|
else:
|
||||||
# 64-bit
|
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
||||||
MAXSIZE = int((1 << 63) - 1)
|
class X(object):
|
||||||
del X
|
def __len__(self):
|
||||||
|
return 1 << 31
|
||||||
|
try:
|
||||||
|
len(X())
|
||||||
|
except OverflowError:
|
||||||
|
# 32-bit
|
||||||
|
MAXSIZE = int((1 << 31) - 1)
|
||||||
|
else:
|
||||||
|
# 64-bit
|
||||||
|
MAXSIZE = int((1 << 63) - 1)
|
||||||
|
del X
|
||||||
|
|
||||||
|
|
||||||
def _add_doc(func, doc):
|
def _add_doc(func, doc):
|
||||||
|
@ -201,12 +205,19 @@ else:
|
||||||
_iteritems = "iteritems"
|
_iteritems = "iteritems"
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
advance_iterator = next
|
||||||
|
except NameError:
|
||||||
|
def advance_iterator(it):
|
||||||
|
return it.next()
|
||||||
|
next = advance_iterator
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
def get_unbound_function(unbound):
|
def get_unbound_function(unbound):
|
||||||
return unbound
|
return unbound
|
||||||
|
|
||||||
|
Iterator = object
|
||||||
advance_iterator = next
|
|
||||||
|
|
||||||
def callable(obj):
|
def callable(obj):
|
||||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||||
|
@ -214,9 +225,10 @@ else:
|
||||||
def get_unbound_function(unbound):
|
def get_unbound_function(unbound):
|
||||||
return unbound.im_func
|
return unbound.im_func
|
||||||
|
|
||||||
|
class Iterator(object):
|
||||||
|
|
||||||
def advance_iterator(it):
|
def next(self):
|
||||||
return it.next()
|
return type(self).__next__(self)
|
||||||
|
|
||||||
callable = callable
|
callable = callable
|
||||||
_add_doc(get_unbound_function,
|
_add_doc(get_unbound_function,
|
||||||
|
@ -231,15 +243,15 @@ get_function_defaults = operator.attrgetter(_func_defaults)
|
||||||
|
|
||||||
def iterkeys(d):
|
def iterkeys(d):
|
||||||
"""Return an iterator over the keys of a dictionary."""
|
"""Return an iterator over the keys of a dictionary."""
|
||||||
return getattr(d, _iterkeys)()
|
return iter(getattr(d, _iterkeys)())
|
||||||
|
|
||||||
def itervalues(d):
|
def itervalues(d):
|
||||||
"""Return an iterator over the values of a dictionary."""
|
"""Return an iterator over the values of a dictionary."""
|
||||||
return getattr(d, _itervalues)()
|
return iter(getattr(d, _itervalues)())
|
||||||
|
|
||||||
def iteritems(d):
|
def iteritems(d):
|
||||||
"""Return an iterator over the (key, value) pairs of a dictionary."""
|
"""Return an iterator over the (key, value) pairs of a dictionary."""
|
||||||
return getattr(d, _iteritems)()
|
return iter(getattr(d, _iteritems)())
|
||||||
|
|
||||||
|
|
||||||
if PY3:
|
if PY3:
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from django.utils import six
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
import warnings
|
import warnings
|
||||||
from gzip import GzipFile
|
from gzip import GzipFile
|
||||||
from django.utils.six.moves import html_entities
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.functional import allow_lazy, SimpleLazyObject
|
||||||
|
from django.utils import six
|
||||||
|
from django.utils.six.moves import html_entities
|
||||||
|
from django.utils.translation import ugettext_lazy, ugettext as _, pgettext
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
if not six.PY3:
|
if not six.PY3:
|
||||||
# Import force_unicode even though this module doesn't use it, because some
|
# Import force_unicode even though this module doesn't use it, because some
|
||||||
# people rely on it being here.
|
# people rely on it being here.
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
from django.utils.functional import allow_lazy, SimpleLazyObject
|
|
||||||
from django.utils import six
|
|
||||||
from django.utils.translation import ugettext_lazy, ugettext as _, pgettext
|
|
||||||
from django.utils.safestring import mark_safe
|
|
||||||
|
|
||||||
# Capitalizes the first letter of a string.
|
# Capitalizes the first letter of a string.
|
||||||
capfirst = lambda x: x and force_text(x)[0].upper() + force_text(x)[1:]
|
capfirst = lambda x: x and force_text(x)[0].upper() + force_text(x)[1:]
|
||||||
|
|
|
@ -9,7 +9,7 @@ import gettext as gettext_module
|
||||||
from threading import local
|
from threading import local
|
||||||
|
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.encoding import smart_str, smart_text
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.safestring import mark_safe, SafeData
|
from django.utils.safestring import mark_safe, SafeData
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
@ -454,7 +454,7 @@ def templatize(src, origin=None):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.template import (Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK,
|
from django.template import (Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK,
|
||||||
TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK)
|
TOKEN_COMMENT, TRANSLATOR_COMMENT_MARK)
|
||||||
src = smart_text(src, settings.FILE_CHARSET)
|
src = force_text(src, settings.FILE_CHARSET)
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
message_context = None
|
message_context = None
|
||||||
intrans = False
|
intrans = False
|
||||||
|
@ -469,7 +469,7 @@ def templatize(src, origin=None):
|
||||||
content = ''.join(comment)
|
content = ''.join(comment)
|
||||||
translators_comment_start = None
|
translators_comment_start = None
|
||||||
for lineno, line in enumerate(content.splitlines(True)):
|
for lineno, line in enumerate(content.splitlines(True)):
|
||||||
if line.lstrip().startswith(smart_text(TRANSLATOR_COMMENT_MARK)):
|
if line.lstrip().startswith(TRANSLATOR_COMMENT_MARK):
|
||||||
translators_comment_start = lineno
|
translators_comment_start = lineno
|
||||||
for lineno, line in enumerate(content.splitlines(True)):
|
for lineno, line in enumerate(content.splitlines(True)):
|
||||||
if translators_comment_start is not None and lineno >= translators_comment_start:
|
if translators_comment_start is not None and lineno >= translators_comment_start:
|
||||||
|
@ -584,7 +584,7 @@ def templatize(src, origin=None):
|
||||||
out.write(' # %s' % t.contents)
|
out.write(' # %s' % t.contents)
|
||||||
else:
|
else:
|
||||||
out.write(blankout(t.contents, 'X'))
|
out.write(blankout(t.contents, 'X'))
|
||||||
return smart_str(out.getvalue())
|
return force_str(out.getvalue())
|
||||||
|
|
||||||
def parse_accept_lang_header(lang_string):
|
def parse_accept_lang_header(lang_string):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||||
import time
|
import time
|
||||||
from datetime import timedelta, tzinfo
|
from datetime import timedelta, tzinfo
|
||||||
|
|
||||||
from django.utils.encoding import smart_text, smart_str, DEFAULT_LOCALE_ENCODING
|
from django.utils.encoding import force_str, force_text, DEFAULT_LOCALE_ENCODING
|
||||||
|
|
||||||
# Python's doc say: "A tzinfo subclass must have an __init__() method that can
|
# Python's doc say: "A tzinfo subclass must have an __init__() method that can
|
||||||
# be called with no arguments". FixedOffset and LocalTimezone don't honor this
|
# be called with no arguments". FixedOffset and LocalTimezone don't honor this
|
||||||
|
@ -53,7 +53,7 @@ class LocalTimezone(tzinfo):
|
||||||
self._tzname = self.tzname(dt)
|
self._tzname = self.tzname(dt)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str(self._tzname)
|
return force_str(self._tzname)
|
||||||
|
|
||||||
def __getinitargs__(self):
|
def __getinitargs__(self):
|
||||||
return self.__dt,
|
return self.__dt,
|
||||||
|
@ -72,7 +72,7 @@ class LocalTimezone(tzinfo):
|
||||||
|
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
try:
|
try:
|
||||||
return smart_text(time.tzname[self._isdst(dt)],
|
return force_text(time.tzname[self._isdst(dt)],
|
||||||
DEFAULT_LOCALE_ENCODING)
|
DEFAULT_LOCALE_ENCODING)
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -14,7 +14,7 @@ from django.template import Template, Context, TemplateDoesNotExist
|
||||||
from django.template.defaultfilters import force_escape, pprint
|
from django.template.defaultfilters import force_escape, pprint
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.encoding import smart_text, smart_bytes
|
from django.utils.encoding import force_bytes, smart_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
HIDDEN_SETTINGS = re.compile('API|TOKEN|KEY|SECRET|PASS|PROFANITIES_LIST|SIGNATURE')
|
HIDDEN_SETTINGS = re.compile('API|TOKEN|KEY|SECRET|PASS|PROFANITIES_LIST|SIGNATURE')
|
||||||
|
@ -440,7 +440,7 @@ def technical_404_response(request, exception):
|
||||||
'root_urlconf': settings.ROOT_URLCONF,
|
'root_urlconf': settings.ROOT_URLCONF,
|
||||||
'request_path': request.path_info[1:], # Trim leading slash
|
'request_path': request.path_info[1:], # Trim leading slash
|
||||||
'urlpatterns': tried,
|
'urlpatterns': tried,
|
||||||
'reason': smart_bytes(exception, errors='replace'),
|
'reason': force_bytes(exception, errors='replace'),
|
||||||
'request': request,
|
'request': request,
|
||||||
'settings': get_safe_settings(),
|
'settings': get_safe_settings(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -61,7 +61,7 @@ def serve(request, path, document_root=None, show_indexes=False):
|
||||||
mimetype = mimetype or 'application/octet-stream'
|
mimetype = mimetype or 'application/octet-stream'
|
||||||
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
|
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
|
||||||
statobj.st_mtime, statobj.st_size):
|
statobj.st_mtime, statobj.st_size):
|
||||||
return HttpResponseNotModified(content_type=mimetype)
|
return HttpResponseNotModified()
|
||||||
with open(fullpath, 'rb') as f:
|
with open(fullpath, 'rb') as f:
|
||||||
response = HttpResponse(f.read(), content_type=mimetype)
|
response = HttpResponse(f.read(), content_type=mimetype)
|
||||||
response["Last-Modified"] = http_date(statobj.st_mtime)
|
response["Last-Modified"] = http_date(statobj.st_mtime)
|
||||||
|
|
|
@ -191,7 +191,8 @@ modindex_common_prefix = ["django."]
|
||||||
# -- Options for LaTeX output --------------------------------------------------
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
'preamble': '\\DeclareUnicodeCharacter{2265}{\\ensuremath{\\ge}}'
|
'preamble': ('\\DeclareUnicodeCharacter{2264}{\\ensuremath{\\le}}'
|
||||||
|
'\\DeclareUnicodeCharacter{2265}{\\ensuremath{\\ge}}')
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
|
|
@ -185,6 +185,6 @@ would be happy to help you.
|
||||||
|
|
||||||
You might also be interested in posting a job to http://djangogigs.com/ .
|
You might also be interested in posting a job to http://djangogigs.com/ .
|
||||||
If you want to find Django-capable people in your local area, try
|
If you want to find Django-capable people in your local area, try
|
||||||
http://djangopeople.net/ .
|
https://people.djangoproject.com/ .
|
||||||
|
|
||||||
.. _developers for hire page: https://code.djangoproject.com/wiki/DevelopersForHire
|
.. _developers for hire page: https://code.djangoproject.com/wiki/DevelopersForHire
|
||||||
|
|
|
@ -108,7 +108,8 @@ to know about views via the links below:
|
||||||
:doc:`Built-in display views <topics/class-based-views/generic-display>` |
|
:doc:`Built-in display views <topics/class-based-views/generic-display>` |
|
||||||
:doc:`Built-in editing views <topics/class-based-views/generic-editing>` |
|
:doc:`Built-in editing views <topics/class-based-views/generic-editing>` |
|
||||||
:doc:`Using mixins <topics/class-based-views/mixins>` |
|
:doc:`Using mixins <topics/class-based-views/mixins>` |
|
||||||
:doc:`API reference <ref/class-based-views/index>`
|
:doc:`API reference <ref/class-based-views/index>` |
|
||||||
|
:doc:`Flattened index<ref/class-based-views/flattened-index>`
|
||||||
|
|
||||||
* **Advanced:**
|
* **Advanced:**
|
||||||
:doc:`Generating CSV <howto/outputting-csv>` |
|
:doc:`Generating CSV <howto/outputting-csv>` |
|
||||||
|
|
|
@ -77,7 +77,7 @@ record of being helpful on the mailing lists, and a proven desire to dedicate
|
||||||
serious time to Django. In return, they've been granted the coveted commit bit,
|
serious time to Django. In return, they've been granted the coveted commit bit,
|
||||||
and have free rein to hack on all parts of Django.
|
and have free rein to hack on all parts of Django.
|
||||||
|
|
||||||
`Malcolm Tredinnick`_
|
Malcolm Tredinnick
|
||||||
Malcolm originally wanted to be a mathematician, somehow ended up a software
|
Malcolm originally wanted to be a mathematician, somehow ended up a software
|
||||||
developer. He's contributed to many Open Source projects, has served on the
|
developer. He's contributed to many Open Source projects, has served on the
|
||||||
board of the GNOME foundation, and will kick your ass at chess.
|
board of the GNOME foundation, and will kick your ass at chess.
|
||||||
|
@ -85,8 +85,6 @@ and have free rein to hack on all parts of Django.
|
||||||
When he's not busy being an International Man of Mystery, Malcolm lives in
|
When he's not busy being an International Man of Mystery, Malcolm lives in
|
||||||
Sydney, Australia.
|
Sydney, Australia.
|
||||||
|
|
||||||
.. _malcolm tredinnick: http://www.pointy-stick.com/
|
|
||||||
|
|
||||||
`Russell Keith-Magee`_
|
`Russell Keith-Magee`_
|
||||||
Russell studied physics as an undergraduate, and studied neural networks for
|
Russell studied physics as an undergraduate, and studied neural networks for
|
||||||
his PhD. His first job was with a startup in the defense industry developing
|
his PhD. His first job was with a startup in the defense industry developing
|
||||||
|
|
|
@ -0,0 +1,556 @@
|
||||||
|
===========================================
|
||||||
|
Class-based generic views - flattened index
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
This index provides an alternate organization of the reference documentation
|
||||||
|
for class-based views. For each view, the effective attributes and methods from
|
||||||
|
the class tree are represented under that view. For the reference
|
||||||
|
documentation organized by the class which defines the behavior, see
|
||||||
|
:doc:`Class-based views</ref/class-based-views/index>`
|
||||||
|
|
||||||
|
Simple generic views
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
View
|
||||||
|
~~~~
|
||||||
|
.. class:: View()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
|
||||||
|
TemplateView
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
.. class:: TemplateView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateView.get`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateView.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
RedirectView
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
.. class:: RedirectView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.base.RedirectView.permanent`
|
||||||
|
* :attr:`~django.views.generic.base.RedirectView.query_string`
|
||||||
|
* :attr:`~django.views.generic.base.RedirectView.url`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.delete`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.get`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.get_redirect_url`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.options`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.post`
|
||||||
|
* :meth:`~django.views.generic.base.RedirectView.put`
|
||||||
|
|
||||||
|
Detail Views
|
||||||
|
------------
|
||||||
|
|
||||||
|
DetailView
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. class:: DetailView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.detail.BaseDetailView.get`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
List Views
|
||||||
|
----------
|
||||||
|
|
||||||
|
ListView
|
||||||
|
~~~~~~~~
|
||||||
|
.. class:: ListView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.list.BaseListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
Editing views
|
||||||
|
-------------
|
||||||
|
|
||||||
|
FormView
|
||||||
|
~~~~~~~~
|
||||||
|
.. class:: FormView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_valid`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.get`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.post`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.put`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
CreateView
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. class:: CreateView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_valid`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.get`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.post`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.put`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
UpdateView
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. class:: UpdateView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.form_class` [:meth:`~django.views.generic.edit.FormMixin.get_form_class`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.initial` [:meth:`~django.views.generic.edit.FormMixin.get_initial`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_invalid`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.form_valid`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.get`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form`
|
||||||
|
* :meth:`~django.views.generic.edit.FormMixin.get_form_kwargs`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.post`
|
||||||
|
* :meth:`~django.views.generic.edit.ProcessFormView.put`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
DeleteView
|
||||||
|
~~~~~~~~~~
|
||||||
|
.. class:: DeleteView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.edit.DeletionMixin.success_url` [:meth:`~django.views.generic.edit.DeletionMixin.get_success_url`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.edit.DeletionMixin.delete`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.detail.BaseDetailView.get`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.edit.DeletionMixin.post`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
Date-based views
|
||||||
|
----------------
|
||||||
|
|
||||||
|
ArchiveIndexView
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
.. class:: ArchiveIndexView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
YearArchiveView
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
.. class:: YearArchiveView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.dates.BaseYearArchiveView.make_object_list` [:meth:`~django.views.generic.dates.BaseYearArchiveView.get_make_object_list`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
MonthArchiveView
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
.. class:: MonthArchiveView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
WeekArchiveView
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
.. class:: WeekArchiveView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.WeekMixin.week` [:meth:`~django.views.generic.dates.WeekMixin.get_week`]
|
||||||
|
* :attr:`~django.views.generic.dates.WeekMixin.week_format` [:meth:`~django.views.generic.dates.WeekMixin.get_week_format`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
DayArchiveView
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
.. class:: DayArchiveView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
TodayArchiveView
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
.. class:: TodayArchiveView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.allow_empty` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_allow_empty`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.context_object_name` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginate_by` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_paginate_by`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_date_list`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_items`
|
||||||
|
* :meth:`~django.views.generic.dates.BaseDateListView.get_dated_queryset`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.get_paginator`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
||||||
|
|
||||||
|
DateDetailView
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
.. class:: DateDetailView()
|
||||||
|
|
||||||
|
**Attributes** (with optional accessor):
|
||||||
|
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.allow_future` [:meth:`~django.views.generic.dates.DateMixin.get_allow_future`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.context_object_name` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_context_object_name`]
|
||||||
|
* :attr:`~django.views.generic.dates.DateMixin.date_field` [:meth:`~django.views.generic.dates.DateMixin.get_date_field`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day` [:meth:`~django.views.generic.dates.DayMixin.get_day`]
|
||||||
|
* :attr:`~django.views.generic.dates.DayMixin.day_format` [:meth:`~django.views.generic.dates.DayMixin.get_day_format`]
|
||||||
|
* :attr:`~django.views.generic.base.View.http_method_names`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.model`
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month` [:meth:`~django.views.generic.dates.MonthMixin.get_month`]
|
||||||
|
* :attr:`~django.views.generic.dates.MonthMixin.month_format` [:meth:`~django.views.generic.dates.MonthMixin.get_month_format`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.pk_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.queryset` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_queryset`]
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
|
||||||
|
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
|
||||||
|
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
|
||||||
|
* :attr:`~django.views.generic.dates.YearMixin.year_format` [:meth:`~django.views.generic.dates.YearMixin.get_year_format`]
|
||||||
|
|
||||||
|
**Methods**
|
||||||
|
|
||||||
|
* :meth:`~django.views.generic.base.View.as_view`
|
||||||
|
* :meth:`~django.views.generic.base.View.dispatch`
|
||||||
|
* :meth:`~django.views.generic.detail.BaseDetailView.get`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_context_data`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_next_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_next_month`
|
||||||
|
* :meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
|
||||||
|
* :meth:`~django.views.generic.dates.DayMixin.get_previous_day`
|
||||||
|
* :meth:`~django.views.generic.dates.MonthMixin.get_previous_month`
|
||||||
|
* :meth:`~django.views.generic.base.View.head`
|
||||||
|
* :meth:`~django.views.generic.base.View.http_method_not_allowed`
|
||||||
|
* :meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
|
|
@ -13,6 +13,7 @@ Class-based views API reference. For introductory material, see
|
||||||
generic-editing
|
generic-editing
|
||||||
generic-date-based
|
generic-date-based
|
||||||
mixins
|
mixins
|
||||||
|
flattened-index
|
||||||
|
|
||||||
Specification
|
Specification
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -561,8 +561,6 @@ subclass::
|
||||||
|
|
||||||
.. attribute:: ModelAdmin.list_filter
|
.. attribute:: ModelAdmin.list_filter
|
||||||
|
|
||||||
.. versionchanged:: 1.4
|
|
||||||
|
|
||||||
Set ``list_filter`` to activate filters in the right sidebar of the change
|
Set ``list_filter`` to activate filters in the right sidebar of the change
|
||||||
list page of the admin, as illustrated in the following screenshot:
|
list page of the admin, as illustrated in the following screenshot:
|
||||||
|
|
||||||
|
@ -586,6 +584,8 @@ subclass::
|
||||||
class PersonAdmin(UserAdmin):
|
class PersonAdmin(UserAdmin):
|
||||||
list_filter = ('company__name',)
|
list_filter = ('company__name',)
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
* a class inheriting from :mod:`django.contrib.admin.SimpleListFilter`,
|
* a class inheriting from :mod:`django.contrib.admin.SimpleListFilter`,
|
||||||
which you need to provide the ``title`` and ``parameter_name``
|
which you need to provide the ``title`` and ``parameter_name``
|
||||||
attributes to and override the ``lookups`` and ``queryset`` methods,
|
attributes to and override the ``lookups`` and ``queryset`` methods,
|
||||||
|
@ -671,6 +671,8 @@ subclass::
|
||||||
birthday__lte=date(1999, 12, 31)).exists():
|
birthday__lte=date(1999, 12, 31)).exists():
|
||||||
yield ('90s', _('in the nineties'))
|
yield ('90s', _('in the nineties'))
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
* a tuple, where the first element is a field name and the second
|
* a tuple, where the first element is a field name and the second
|
||||||
element is a class inheriting from
|
element is a class inheriting from
|
||||||
:mod:`django.contrib.admin.FieldListFilter`, for example::
|
:mod:`django.contrib.admin.FieldListFilter`, for example::
|
||||||
|
|
|
@ -158,11 +158,13 @@ For example::
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
There's a known bug in Safari/Webkit which causes the named anchor to be
|
There's a `known bug`_ in Safari/Webkit which causes the named anchor to be
|
||||||
forgotten following a redirect. The practical impact for comments is that
|
forgotten following a redirect. The practical impact for comments is that
|
||||||
the Safari/webkit browsers will arrive at the correct page but will not
|
the Safari/webkit browsers will arrive at the correct page but will not
|
||||||
scroll to the named anchor.
|
scroll to the named anchor.
|
||||||
|
|
||||||
|
.. _`known bug`: https://bugs.webkit.org/show_bug.cgi?id=24175
|
||||||
|
|
||||||
.. templatetag:: get_comment_count
|
.. templatetag:: get_comment_count
|
||||||
|
|
||||||
Counting comments
|
Counting comments
|
||||||
|
|
|
@ -84,47 +84,94 @@ AJAX
|
||||||
While the above method can be used for AJAX POST requests, it has some
|
While the above method can be used for AJAX POST requests, it has some
|
||||||
inconveniences: you have to remember to pass the CSRF token in as POST data with
|
inconveniences: you have to remember to pass the CSRF token in as POST data with
|
||||||
every POST request. For this reason, there is an alternative method: on each
|
every POST request. For this reason, there is an alternative method: on each
|
||||||
XMLHttpRequest, set a custom `X-CSRFToken` header to the value of the CSRF
|
XMLHttpRequest, set a custom ``X-CSRFToken`` header to the value of the CSRF
|
||||||
token. This is often easier, because many javascript frameworks provide hooks
|
token. This is often easier, because many javascript frameworks provide hooks
|
||||||
that allow headers to be set on every request. In jQuery, you can use the
|
that allow headers to be set on every request.
|
||||||
``ajaxSend`` event as follows:
|
|
||||||
|
As a first step, you must get the CSRF token itself. The recommended source for
|
||||||
|
the token is the ``csrftoken`` cookie, which will be set if you've enabled CSRF
|
||||||
|
protection for your views as outlined above.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The CSRF token cookie is named ``csrftoken`` by default, but you can control
|
||||||
|
the cookie name via the :setting:`CSRF_COOKIE_NAME` setting.
|
||||||
|
|
||||||
|
Acquiring the token is straightforward:
|
||||||
|
|
||||||
.. code-block:: javascript
|
.. code-block:: javascript
|
||||||
|
|
||||||
jQuery(document).ajaxSend(function(event, xhr, settings) {
|
// using jQuery
|
||||||
function getCookie(name) {
|
function getCookie(name) {
|
||||||
var cookieValue = null;
|
var cookieValue = null;
|
||||||
if (document.cookie && document.cookie != '') {
|
if (document.cookie && document.cookie != '') {
|
||||||
var cookies = document.cookie.split(';');
|
var cookies = document.cookie.split(';');
|
||||||
for (var i = 0; i < cookies.length; i++) {
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
var cookie = jQuery.trim(cookies[i]);
|
var cookie = jQuery.trim(cookies[i]);
|
||||||
// Does this cookie string begin with the name we want?
|
// Does this cookie string begin with the name we want?
|
||||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cookieValue;
|
|
||||||
}
|
|
||||||
function sameOrigin(url) {
|
|
||||||
// url could be relative or scheme relative or absolute
|
|
||||||
var host = document.location.host; // host + port
|
|
||||||
var protocol = document.location.protocol;
|
|
||||||
var sr_origin = '//' + host;
|
|
||||||
var origin = protocol + sr_origin;
|
|
||||||
// Allow absolute or scheme relative URLs to same origin
|
|
||||||
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
|
|
||||||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
|
|
||||||
// or any other URL that isn't scheme relative or absolute i.e relative.
|
|
||||||
!(/^(\/\/|http:|https:).*/.test(url));
|
|
||||||
}
|
|
||||||
function safeMethod(method) {
|
|
||||||
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
|
||||||
}
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
var csrftoken = getCookie('csrftoken');
|
||||||
|
|
||||||
if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
|
The above code could be simplified by using the `jQuery cookie plugin
|
||||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
|
<http://plugins.jquery.com/project/Cookie>`_ to replace ``getCookie``:
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
var csrftoken = $.cookie('csrftoken');
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The CSRF token is also present in the DOM, but only if explicitly included
|
||||||
|
using :ttag:`csrf_token` in a template. The cookie contains the canonical
|
||||||
|
token; the ``CsrfViewMiddleware`` will prefer the cookie to the token in
|
||||||
|
the DOM. Regardless, you're guaranteed to have the cookie if the token is
|
||||||
|
present in the DOM, so you should use the cookie!
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
If your view is not rendering a template containing the :ttag:`csrf_token`
|
||||||
|
template tag, Django might not set the CSRF token cookie. This is common in
|
||||||
|
cases where forms are dynamically added to the page. To address this case,
|
||||||
|
Django provides a view decorator which forces setting of the cookie:
|
||||||
|
:func:`~django.views.decorators.csrf.ensure_csrf_cookie`.
|
||||||
|
|
||||||
|
Finally, you'll have to actually set the header on your AJAX request, while
|
||||||
|
protecting the CSRF token from being sent to other domains.
|
||||||
|
|
||||||
|
.. code-block:: javascript
|
||||||
|
|
||||||
|
function csrfSafeMethod(method) {
|
||||||
|
// these HTTP methods do not require CSRF protection
|
||||||
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||||
|
}
|
||||||
|
function sameOrigin(url) {
|
||||||
|
// test that a given url is a same-origin URL
|
||||||
|
// url could be relative or scheme relative or absolute
|
||||||
|
var host = document.location.host; // host + port
|
||||||
|
var protocol = document.location.protocol;
|
||||||
|
var sr_origin = '//' + host;
|
||||||
|
var origin = protocol + sr_origin;
|
||||||
|
// Allow absolute or scheme relative URLs to same origin
|
||||||
|
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
|
||||||
|
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
|
||||||
|
// or any other URL that isn't scheme relative or absolute i.e relative.
|
||||||
|
!(/^(\/\/|http:|https:).*/.test(url));
|
||||||
|
}
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function(xhr, settings) {
|
||||||
|
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
|
||||||
|
// Send the token to same-origin, relative URLs only.
|
||||||
|
// Send the token only if the method warrants CSRF protection
|
||||||
|
// Using the CSRFToken value acquired earlier
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -133,18 +180,32 @@ that allow headers to be set on every request. In jQuery, you can use the
|
||||||
Due to a bug introduced in jQuery 1.5, the example above will not work
|
Due to a bug introduced in jQuery 1.5, the example above will not work
|
||||||
correctly on that version. Make sure you are running at least jQuery 1.5.1.
|
correctly on that version. Make sure you are running at least jQuery 1.5.1.
|
||||||
|
|
||||||
Adding this to a javascript file that is included on your site will ensure that
|
You can use `settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in
|
||||||
AJAX POST requests that are made via jQuery will not be caught by the CSRF
|
jQuery 1.5 and newer in order to replace the `sameOrigin` logic above:
|
||||||
protection.
|
|
||||||
|
|
||||||
The above code could be simplified by using the `jQuery cookie plugin
|
.. code-block:: javascript
|
||||||
<http://plugins.jquery.com/project/Cookie>`_ to replace ``getCookie``, and
|
|
||||||
`settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in jQuery 1.5 and
|
|
||||||
later to replace ``sameOrigin``.
|
|
||||||
|
|
||||||
In addition, if the CSRF cookie has not been sent to the client by use of
|
function csrfSafeMethod(method) {
|
||||||
:ttag:`csrf_token`, you may need to ensure the client receives the cookie by
|
// these HTTP methods do not require CSRF protection
|
||||||
using :func:`~django.views.decorators.csrf.ensure_csrf_cookie`.
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||||
|
}
|
||||||
|
$.ajaxSetup({
|
||||||
|
crossDomain: false, // obviates need for sameOrigin test
|
||||||
|
beforeSend: function(xhr, settings) {
|
||||||
|
if (!csrfSafeMethod(settings.type)) {
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In a `security release blogpost`_, a simpler "same origin test" example
|
||||||
|
was provided which only checked for a relative URL. The ``sameOrigin``
|
||||||
|
test above supersedes that example—it works for edge cases like
|
||||||
|
scheme-relative or absolute URLs for the same domain.
|
||||||
|
|
||||||
|
.. _security release blogpost: https://www.djangoproject.com/weblog/2011/feb/08/security/
|
||||||
|
|
||||||
Other template engines
|
Other template engines
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -42,6 +42,16 @@ To install the flatpages app, follow these steps:
|
||||||
2. Add ``'django.contrib.flatpages'`` to your :setting:`INSTALLED_APPS`
|
2. Add ``'django.contrib.flatpages'`` to your :setting:`INSTALLED_APPS`
|
||||||
setting.
|
setting.
|
||||||
|
|
||||||
|
Then either:
|
||||||
|
|
||||||
|
3. Add an entry in your URLconf. For example::
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
('^pages/', include('django.contrib.flatpages.urls')),
|
||||||
|
)
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
|
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
|
||||||
to your :setting:`MIDDLEWARE_CLASSES` setting.
|
to your :setting:`MIDDLEWARE_CLASSES` setting.
|
||||||
|
|
||||||
|
@ -57,8 +67,38 @@ and ``django_flatpage_sites``. ``django_flatpage`` is a simple lookup table
|
||||||
that simply maps a URL to a title and bunch of text content.
|
that simply maps a URL to a title and bunch of text content.
|
||||||
``django_flatpage_sites`` associates a flatpage with a site.
|
``django_flatpage_sites`` associates a flatpage with a site.
|
||||||
|
|
||||||
|
Using the URLconf
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
There are several ways to include the flat pages in your URLconf. You can
|
||||||
|
dedicate a particular path to flat pages::
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
('^pages/', include('django.contrib.flatpages.urls')),
|
||||||
|
)
|
||||||
|
|
||||||
|
You can also set it up as a "catchall" pattern. In this case, it is important
|
||||||
|
to place the pattern at the end of the other urlpatterns::
|
||||||
|
|
||||||
|
# Your other patterns here
|
||||||
|
urlpatterns += patterns('django.contrib.flatpages.views',
|
||||||
|
(r'^(?P<url>.*)$', 'flatpage'),
|
||||||
|
)
|
||||||
|
|
||||||
|
Another common setup is to use flat pages for a limited set of known pages and
|
||||||
|
to hard code the urls, so you can reference them with the :ttag:`url` template
|
||||||
|
tag::
|
||||||
|
|
||||||
|
urlpatterns += patterns('django.contrib.flatpages.views',
|
||||||
|
url(r'^about-us/$', 'flatpage', {'url': '/about-us/'}, name='about'),
|
||||||
|
url(r'^license/$', 'flatpage', {'url': '/license/'}, name='license'),
|
||||||
|
)
|
||||||
|
|
||||||
|
Using the middleware
|
||||||
|
--------------------
|
||||||
|
|
||||||
The :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
|
The :class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
|
||||||
does all of the work.
|
can do all of the work.
|
||||||
|
|
||||||
.. class:: FlatpageFallbackMiddleware
|
.. class:: FlatpageFallbackMiddleware
|
||||||
|
|
||||||
|
@ -255,4 +295,3 @@ For example:
|
||||||
{% get_flatpages '/about/' as about_pages %}
|
{% get_flatpages '/about/' as about_pages %}
|
||||||
{% get_flatpages about_prefix as about_pages %}
|
{% get_flatpages about_prefix as about_pages %}
|
||||||
{% get_flatpages '/about/' for someuser as about_pages %}
|
{% get_flatpages '/about/' for someuser as about_pages %}
|
||||||
|
|
||||||
|
|
|
@ -582,7 +582,7 @@ Creating a spatial database for SpatiaLite
|
||||||
After you've installed SpatiaLite, you'll need to create a number of spatial
|
After you've installed SpatiaLite, you'll need to create a number of spatial
|
||||||
metadata tables in your database in order to perform spatial queries.
|
metadata tables in your database in order to perform spatial queries.
|
||||||
|
|
||||||
If you're using SpatiaLite 3.0 or newer, use the ``spatialite`` utility to
|
If you're using SpatiaLite 2.4 or newer, use the ``spatialite`` utility to
|
||||||
call the ``InitSpatialMetaData()`` function, like this::
|
call the ``InitSpatialMetaData()`` function, like this::
|
||||||
|
|
||||||
$ spatialite geodjango.db "SELECT InitSpatialMetaData();"
|
$ spatialite geodjango.db "SELECT InitSpatialMetaData();"
|
||||||
|
@ -593,12 +593,10 @@ call the ``InitSpatialMetaData()`` function, like this::
|
||||||
You can safely ignore the error messages shown. When you've done this, you can
|
You can safely ignore the error messages shown. When you've done this, you can
|
||||||
skip the rest of this section.
|
skip the rest of this section.
|
||||||
|
|
||||||
If you're using a version of SpatiaLite older than 3.0, you'll need to download
|
If you're using SpatiaLite 2.3, you'll need to download a
|
||||||
a database-initialization file and execute its SQL queries in your database.
|
database-initialization file and execute its SQL queries in your database.
|
||||||
|
|
||||||
First, get it from the appropriate SpatiaLite Resources page (
|
First, get it from the `SpatiaLite Resources`__ page::
|
||||||
http://www.gaia-gis.it/spatialite-2.3.1/resources.html for 2.3 or
|
|
||||||
http://www.gaia-gis.it/spatialite-2.4.0/ for 2.4)::
|
|
||||||
|
|
||||||
$ wget http://www.gaia-gis.it/spatialite-2.3.1/init_spatialite-2.3.sql.gz
|
$ wget http://www.gaia-gis.it/spatialite-2.3.1/init_spatialite-2.3.sql.gz
|
||||||
$ gunzip init_spatialite-2.3.sql.gz
|
$ gunzip init_spatialite-2.3.sql.gz
|
||||||
|
@ -613,6 +611,8 @@ Then, use the ``spatialite`` command to initialize a spatial database::
|
||||||
you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key
|
you want to use. Use the same in the :setting:`DATABASES` ``"name"`` key
|
||||||
inside your ``settings.py``.
|
inside your ``settings.py``.
|
||||||
|
|
||||||
|
__ http://www.gaia-gis.it/spatialite-2.3.1/resources.html
|
||||||
|
|
||||||
Add ``django.contrib.gis`` to :setting:`INSTALLED_APPS`
|
Add ``django.contrib.gis`` to :setting:`INSTALLED_APPS`
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
|
@ -820,8 +820,10 @@ Download the framework packages for:
|
||||||
* GDAL
|
* GDAL
|
||||||
|
|
||||||
Install the packages in the order they are listed above, as the GDAL and SQLite
|
Install the packages in the order they are listed above, as the GDAL and SQLite
|
||||||
packages require the packages listed before them. Afterwards, you can also
|
packages require the packages listed before them.
|
||||||
install the KyngChaos binary packages for `PostgreSQL and PostGIS`__.
|
|
||||||
|
Afterwards, you can also install the KyngChaos binary packages for `PostgreSQL
|
||||||
|
and PostGIS`__.
|
||||||
|
|
||||||
After installing the binary packages, you'll want to add the following to
|
After installing the binary packages, you'll want to add the following to
|
||||||
your ``.profile`` to be able to run the package programs from the command-line::
|
your ``.profile`` to be able to run the package programs from the command-line::
|
||||||
|
|
|
@ -119,7 +119,7 @@ Settings
|
||||||
``SPATIALITE_SQL``
|
``SPATIALITE_SQL``
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Only relevant when using a SpatiaLite version older than 3.0.
|
Only relevant when using a SpatiaLite version 2.3.
|
||||||
|
|
||||||
By default, the GeoDjango test runner looks for the :ref:`file containing the
|
By default, the GeoDjango test runner looks for the :ref:`file containing the
|
||||||
SpatiaLite dababase-initialization SQL code <create_spatialite_db>` in the
|
SpatiaLite dababase-initialization SQL code <create_spatialite_db>` in the
|
||||||
|
|
|
@ -671,6 +671,17 @@ of abstraction::
|
||||||
|
|
||||||
__ http://spatialreference.org/ref/epsg/32140/
|
__ http://spatialreference.org/ref/epsg/32140/
|
||||||
|
|
||||||
|
.. admonition:: Raw queries
|
||||||
|
|
||||||
|
When using :doc:`raw queries </topics/db/sql>`, you should generally wrap
|
||||||
|
your geometry fields with the ``asText()`` SQL function so as the field
|
||||||
|
value will be recognized by GEOS::
|
||||||
|
|
||||||
|
City.objects.raw('SELECT id, name, asText(point) from myapp_city')
|
||||||
|
|
||||||
|
This is not absolutely required by PostGIS, but generally you should only
|
||||||
|
use raw queries when you know exactly what you are doing.
|
||||||
|
|
||||||
Lazy Geometries
|
Lazy Geometries
|
||||||
---------------
|
---------------
|
||||||
Geometries come to GeoDjango in a standardized textual representation. Upon
|
Geometries come to GeoDjango in a standardized textual representation. Upon
|
||||||
|
|
|
@ -91,14 +91,18 @@ The ``ContentFile`` Class
|
||||||
.. class:: ContentFile(File)
|
.. class:: ContentFile(File)
|
||||||
|
|
||||||
The ``ContentFile`` class inherits from :class:`~django.core.files.File`,
|
The ``ContentFile`` class inherits from :class:`~django.core.files.File`,
|
||||||
but unlike :class:`~django.core.files.File` it operates on string content,
|
but unlike :class:`~django.core.files.File` it operates on string content
|
||||||
rather than an actual file. For example::
|
(bytes also supported), rather than an actual file. For example::
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
|
|
||||||
f1 = ContentFile(b"my string content")
|
f1 = ContentFile("esta sentencia está en español")
|
||||||
f2 = ContentFile("my unicode content encoded as UTF-8".encode('UTF-8'))
|
f2 = ContentFile(b"these are bytes")
|
||||||
|
|
||||||
|
.. versionchanged:: 1.5
|
||||||
|
|
||||||
|
ContentFile also accepts Unicode strings.
|
||||||
|
|
||||||
.. currentmodule:: django.core.files.images
|
.. currentmodule:: django.core.files.images
|
||||||
|
|
||||||
|
|
|
@ -70,8 +70,8 @@ If ``True``, the field is allowed to be blank. Default is ``False``.
|
||||||
|
|
||||||
Note that this is different than :attr:`~Field.null`. :attr:`~Field.null` is
|
Note that this is different than :attr:`~Field.null`. :attr:`~Field.null` is
|
||||||
purely database-related, whereas :attr:`~Field.blank` is validation-related. If
|
purely database-related, whereas :attr:`~Field.blank` is validation-related. If
|
||||||
a field has ``blank=True``, validation on Django's admin site will allow entry
|
a field has ``blank=True``, form validation will allow entry of an empty value.
|
||||||
of an empty value. If a field has ``blank=False``, the field will be required.
|
If a field has ``blank=False``, the field will be required.
|
||||||
|
|
||||||
.. _field-choices:
|
.. _field-choices:
|
||||||
|
|
||||||
|
@ -81,14 +81,11 @@ of an empty value. If a field has ``blank=False``, the field will be required.
|
||||||
.. attribute:: Field.choices
|
.. attribute:: Field.choices
|
||||||
|
|
||||||
An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this
|
An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this
|
||||||
field.
|
field. If this is given, the default form widget will be a select box with
|
||||||
|
these choices instead of the standard text field.
|
||||||
|
|
||||||
If this is given, Django's admin will use a select box instead of the standard
|
The first element in each tuple is the actual value to be stored, and the
|
||||||
text field and will limit choices to the choices given.
|
second element is the human-readable name. For example::
|
||||||
|
|
||||||
A choices list is an iterable of 2-tuples; the first element in each
|
|
||||||
tuple is the actual value to be stored, and the second element is the
|
|
||||||
human-readable name. For example::
|
|
||||||
|
|
||||||
YEAR_IN_SCHOOL_CHOICES = (
|
YEAR_IN_SCHOOL_CHOICES = (
|
||||||
('FR', 'Freshman'),
|
('FR', 'Freshman'),
|
||||||
|
@ -176,7 +173,7 @@ scenes.
|
||||||
|
|
||||||
.. attribute:: Field.db_index
|
.. attribute:: Field.db_index
|
||||||
|
|
||||||
If ``True``, djadmin:`django-admin.py sqlindexes <sqlindexes>` will output a
|
If ``True``, :djadmin:`django-admin.py sqlindexes <sqlindexes>` will output a
|
||||||
``CREATE INDEX`` statement for this field.
|
``CREATE INDEX`` statement for this field.
|
||||||
|
|
||||||
``db_tablespace``
|
``db_tablespace``
|
||||||
|
@ -203,8 +200,8 @@ callable it will be called every time a new object is created.
|
||||||
|
|
||||||
.. attribute:: Field.editable
|
.. attribute:: Field.editable
|
||||||
|
|
||||||
If ``False``, the field will not be editable in the admin or via forms
|
If ``False``, the field will not be displayed in the admin or any other
|
||||||
automatically generated from the model class. Default is ``True``.
|
:class:`~django.forms.ModelForm`. Default is ``True``.
|
||||||
|
|
||||||
``error_messages``
|
``error_messages``
|
||||||
------------------
|
------------------
|
||||||
|
@ -224,11 +221,11 @@ the `Field types`_ section below.
|
||||||
|
|
||||||
.. attribute:: Field.help_text
|
.. attribute:: Field.help_text
|
||||||
|
|
||||||
Extra "help" text to be displayed under the field on the object's admin form.
|
Extra "help" text to be displayed with the form widget. It's useful for
|
||||||
It's useful for documentation even if your object doesn't have an admin form.
|
documentation even if your field isn't used on a form.
|
||||||
|
|
||||||
Note that this value is *not* HTML-escaped when it's displayed in the admin
|
Note that this value is *not* HTML-escaped in automatically-generated
|
||||||
interface. This lets you include HTML in :attr:`~Field.help_text` if you so
|
forms. This lets you include HTML in :attr:`~Field.help_text` if you so
|
||||||
desire. For example::
|
desire. For example::
|
||||||
|
|
||||||
help_text="Please use the following format: <em>YYYY-MM-DD</em>."
|
help_text="Please use the following format: <em>YYYY-MM-DD</em>."
|
||||||
|
@ -259,7 +256,7 @@ Only one primary key is allowed on an object.
|
||||||
|
|
||||||
If ``True``, this field must be unique throughout the table.
|
If ``True``, this field must be unique throughout the table.
|
||||||
|
|
||||||
This is enforced at the database level and at the Django admin-form level. If
|
This is enforced at the database level and by model validation. If
|
||||||
you try to save a model with a duplicate value in a :attr:`~Field.unique`
|
you try to save a model with a duplicate value in a :attr:`~Field.unique`
|
||||||
field, a :exc:`django.db.IntegrityError` will be raised by the model's
|
field, a :exc:`django.db.IntegrityError` will be raised by the model's
|
||||||
:meth:`~django.db.models.Model.save` method.
|
:meth:`~django.db.models.Model.save` method.
|
||||||
|
@ -279,7 +276,7 @@ For example, if you have a field ``title`` that has
|
||||||
``unique_for_date="pub_date"``, then Django wouldn't allow the entry of two
|
``unique_for_date="pub_date"``, then Django wouldn't allow the entry of two
|
||||||
records with the same ``title`` and ``pub_date``.
|
records with the same ``title`` and ``pub_date``.
|
||||||
|
|
||||||
This is enforced at the Django admin-form level but not at the database level.
|
This is enforced by model validation but not at the database level.
|
||||||
|
|
||||||
``unique_for_month``
|
``unique_for_month``
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -337,7 +334,7 @@ otherwise. See :ref:`automatic-primary-key-fields`.
|
||||||
|
|
||||||
A 64 bit integer, much like an :class:`IntegerField` except that it is
|
A 64 bit integer, much like an :class:`IntegerField` except that it is
|
||||||
guaranteed to fit numbers from -9223372036854775808 to 9223372036854775807. The
|
guaranteed to fit numbers from -9223372036854775808 to 9223372036854775807. The
|
||||||
admin represents this as an ``<input type="text">`` (a single-line input).
|
default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
|
|
||||||
``BooleanField``
|
``BooleanField``
|
||||||
|
@ -347,7 +344,8 @@ admin represents this as an ``<input type="text">`` (a single-line input).
|
||||||
|
|
||||||
A true/false field.
|
A true/false field.
|
||||||
|
|
||||||
The admin represents this as a checkbox.
|
The default form widget for this field is a
|
||||||
|
:class:`~django.forms.CheckboxInput`.
|
||||||
|
|
||||||
If you need to accept :attr:`~Field.null` values then use
|
If you need to accept :attr:`~Field.null` values then use
|
||||||
:class:`NullBooleanField` instead.
|
:class:`NullBooleanField` instead.
|
||||||
|
@ -361,7 +359,7 @@ A string field, for small- to large-sized strings.
|
||||||
|
|
||||||
For large amounts of text, use :class:`~django.db.models.TextField`.
|
For large amounts of text, use :class:`~django.db.models.TextField`.
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` (a single-line input).
|
The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
:class:`CharField` has one extra required argument:
|
:class:`CharField` has one extra required argument:
|
||||||
|
|
||||||
|
@ -414,9 +412,10 @@ optional arguments:
|
||||||
for creation of timestamps. Note that the current date is *always* used;
|
for creation of timestamps. Note that the current date is *always* used;
|
||||||
it's not just a default value that you can override.
|
it's not just a default value that you can override.
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` with a JavaScript
|
The default form widget for this field is a
|
||||||
calendar, and a shortcut for "Today". Includes an additional ``invalid_date``
|
:class:`~django.forms.TextInput`. The admin adds a JavaScript calendar,
|
||||||
error message key.
|
and a shortcut for "Today". Includes an additional ``invalid_date`` error
|
||||||
|
message key.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
As currently implemented, setting ``auto_now`` or ``auto_now_add`` to
|
As currently implemented, setting ``auto_now`` or ``auto_now_add`` to
|
||||||
|
@ -431,8 +430,9 @@ error message key.
|
||||||
A date and time, represented in Python by a ``datetime.datetime`` instance.
|
A date and time, represented in Python by a ``datetime.datetime`` instance.
|
||||||
Takes the same extra arguments as :class:`DateField`.
|
Takes the same extra arguments as :class:`DateField`.
|
||||||
|
|
||||||
The admin represents this as two ``<input type="text">`` fields, with
|
The default form widget for this field is a single
|
||||||
JavaScript shortcuts.
|
:class:`~django.forms.TextInput`. The admin uses two separate
|
||||||
|
:class:`~django.forms.TextInput` widgets with JavaScript shortcuts.
|
||||||
|
|
||||||
``DecimalField``
|
``DecimalField``
|
||||||
----------------
|
----------------
|
||||||
|
@ -461,7 +461,7 @@ decimal places::
|
||||||
|
|
||||||
models.DecimalField(..., max_digits=19, decimal_places=10)
|
models.DecimalField(..., max_digits=19, decimal_places=10)
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` (a single-line input).
|
The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -539,8 +539,8 @@ Also has one optional argument:
|
||||||
Optional. A storage object, which handles the storage and retrieval of your
|
Optional. A storage object, which handles the storage and retrieval of your
|
||||||
files. See :doc:`/topics/files` for details on how to provide this object.
|
files. See :doc:`/topics/files` for details on how to provide this object.
|
||||||
|
|
||||||
The admin represents this field as an ``<input type="file">`` (a file-upload
|
The default form widget for this field is a
|
||||||
widget).
|
:class:`~django.forms.widgets.FileInput`.
|
||||||
|
|
||||||
Using a :class:`FileField` or an :class:`ImageField` (see below) in a model
|
Using a :class:`FileField` or an :class:`ImageField` (see below) in a model
|
||||||
takes a few steps:
|
takes a few steps:
|
||||||
|
@ -725,7 +725,7 @@ can change the maximum length using the :attr:`~CharField.max_length` argument.
|
||||||
|
|
||||||
A floating-point number represented in Python by a ``float`` instance.
|
A floating-point number represented in Python by a ``float`` instance.
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` (a single-line input).
|
The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
.. _floatfield_vs_decimalfield:
|
.. _floatfield_vs_decimalfield:
|
||||||
|
|
||||||
|
@ -776,16 +776,16 @@ length using the :attr:`~CharField.max_length` argument.
|
||||||
|
|
||||||
.. class:: IntegerField([**options])
|
.. class:: IntegerField([**options])
|
||||||
|
|
||||||
An integer. The admin represents this as an ``<input type="text">`` (a
|
An integer. The default form widget for this field is a
|
||||||
single-line input).
|
:class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
``IPAddressField``
|
``IPAddressField``
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. class:: IPAddressField([**options])
|
.. class:: IPAddressField([**options])
|
||||||
|
|
||||||
An IP address, in string format (e.g. "192.0.2.30"). The admin represents this
|
An IP address, in string format (e.g. "192.0.2.30"). The default form widget
|
||||||
as an ``<input type="text">`` (a single-line input).
|
for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
``GenericIPAddressField``
|
``GenericIPAddressField``
|
||||||
-------------------------
|
-------------------------
|
||||||
|
@ -795,8 +795,8 @@ as an ``<input type="text">`` (a single-line input).
|
||||||
.. versionadded:: 1.4
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
An IPv4 or IPv6 address, in string format (e.g. ``192.0.2.30`` or
|
An IPv4 or IPv6 address, in string format (e.g. ``192.0.2.30`` or
|
||||||
``2a02:42fe::4``). The admin represents this as an ``<input type="text">``
|
``2a02:42fe::4``). The default form widget for this field is a
|
||||||
(a single-line input).
|
:class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
The IPv6 address normalization follows :rfc:`4291#section-2.2` section 2.2,
|
The IPv6 address normalization follows :rfc:`4291#section-2.2` section 2.2,
|
||||||
including using the IPv4 format suggested in paragraph 3 of that section, like
|
including using the IPv4 format suggested in paragraph 3 of that section, like
|
||||||
|
@ -823,8 +823,8 @@ are converted to lowercase.
|
||||||
.. class:: NullBooleanField([**options])
|
.. class:: NullBooleanField([**options])
|
||||||
|
|
||||||
Like a :class:`BooleanField`, but allows ``NULL`` as one of the options. Use
|
Like a :class:`BooleanField`, but allows ``NULL`` as one of the options. Use
|
||||||
this instead of a :class:`BooleanField` with ``null=True``. The admin represents
|
this instead of a :class:`BooleanField` with ``null=True``. The default form
|
||||||
this as a ``<select>`` box with "Unknown", "Yes" and "No" choices.
|
widget for this field is a :class:`~django.forms.NullBooleanSelect`.
|
||||||
|
|
||||||
``PositiveIntegerField``
|
``PositiveIntegerField``
|
||||||
------------------------
|
------------------------
|
||||||
|
@ -875,8 +875,8 @@ Like an :class:`IntegerField`, but only allows values under a certain
|
||||||
|
|
||||||
.. class:: TextField([**options])
|
.. class:: TextField([**options])
|
||||||
|
|
||||||
A large text field. The admin represents this as a ``<textarea>`` (a multi-line
|
A large text field. The default form widget for this field is a
|
||||||
input).
|
:class:`~django.forms.Textarea`.
|
||||||
|
|
||||||
.. admonition:: MySQL users
|
.. admonition:: MySQL users
|
||||||
|
|
||||||
|
@ -893,8 +893,8 @@ input).
|
||||||
A time, represented in Python by a ``datetime.time`` instance. Accepts the same
|
A time, represented in Python by a ``datetime.time`` instance. Accepts the same
|
||||||
auto-population options as :class:`DateField`.
|
auto-population options as :class:`DateField`.
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` with some JavaScript
|
The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
shortcuts.
|
The admin adds some JavaScript shortcuts.
|
||||||
|
|
||||||
``URLField``
|
``URLField``
|
||||||
------------
|
------------
|
||||||
|
@ -903,7 +903,7 @@ shortcuts.
|
||||||
|
|
||||||
A :class:`CharField` for a URL.
|
A :class:`CharField` for a URL.
|
||||||
|
|
||||||
The admin represents this as an ``<input type="text">`` (a single-line input).
|
The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||||
|
|
||||||
Like all :class:`CharField` subclasses, :class:`URLField` takes the optional
|
Like all :class:`CharField` subclasses, :class:`URLField` takes the optional
|
||||||
:attr:`~CharField.max_length`argument. If you don't specify
|
:attr:`~CharField.max_length`argument. If you don't specify
|
||||||
|
@ -979,9 +979,9 @@ define the details of how the relation works.
|
||||||
.. attribute:: ForeignKey.limit_choices_to
|
.. attribute:: ForeignKey.limit_choices_to
|
||||||
|
|
||||||
A dictionary of lookup arguments and values (see :doc:`/topics/db/queries`)
|
A dictionary of lookup arguments and values (see :doc:`/topics/db/queries`)
|
||||||
that limit the available admin choices for this object. Use this with
|
that limit the available admin or ModelForm choices for this object. Use
|
||||||
functions from the Python ``datetime`` module to limit choices of objects by
|
this with functions from the Python ``datetime`` module to limit choices of
|
||||||
date. For example::
|
objects by date. For example::
|
||||||
|
|
||||||
limit_choices_to = {'pub_date__lte': datetime.now}
|
limit_choices_to = {'pub_date__lte': datetime.now}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ that, you need to :meth:`~Model.save()`.
|
||||||
2. Add a method on a custom manager (usually preferred)::
|
2. Add a method on a custom manager (usually preferred)::
|
||||||
|
|
||||||
class BookManager(models.Manager):
|
class BookManager(models.Manager):
|
||||||
def create_book(title):
|
def create_book(self, title):
|
||||||
book = self.create(title=title)
|
book = self.create(title=title)
|
||||||
# do something with the book
|
# do something with the book
|
||||||
return book
|
return book
|
||||||
|
@ -459,9 +459,9 @@ using ``__str__()`` like this::
|
||||||
last_name = models.CharField(max_length=50)
|
last_name = models.CharField(max_length=50)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# Note use of django.utils.encoding.smart_bytes() here because
|
# Note use of django.utils.encoding.force_bytes() here because
|
||||||
# first_name and last_name will be unicode strings.
|
# first_name and last_name will be unicode strings.
|
||||||
return smart_bytes('%s %s' % (self.first_name, self.last_name))
|
return force_bytes('%s %s' % (self.first_name, self.last_name))
|
||||||
|
|
||||||
``get_absolute_url``
|
``get_absolute_url``
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -2064,7 +2064,7 @@ Note this is only available in MySQL and requires direct manipulation of the
|
||||||
database to add the full-text index. By default Django uses BOOLEAN MODE for
|
database to add the full-text index. By default Django uses BOOLEAN MODE for
|
||||||
full text searches. See the `MySQL documentation`_ for additional details.
|
full text searches. See the `MySQL documentation`_ for additional details.
|
||||||
|
|
||||||
.. _MySQL documentation: http://dev.mysql.com/doc/refman/5.1/en/fulltext-boolean.html>
|
.. _MySQL documentation: http://dev.mysql.com/doc/refman/5.1/en/fulltext-boolean.html
|
||||||
|
|
||||||
|
|
||||||
.. fieldlookup:: regex
|
.. fieldlookup:: regex
|
||||||
|
@ -2236,4 +2236,3 @@ Variance
|
||||||
extension.
|
extension.
|
||||||
|
|
||||||
.. _SQLite documentation: http://www.sqlite.org/contrib
|
.. _SQLite documentation: http://www.sqlite.org/contrib
|
||||||
|
|
||||||
|
|
|
@ -731,10 +731,11 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
|
||||||
|
|
||||||
.. class:: HttpResponseRedirect
|
.. class:: HttpResponseRedirect
|
||||||
|
|
||||||
The constructor takes a single argument -- the path to redirect to. This
|
The first argument to the constructor is required -- the path to redirect
|
||||||
can be a fully qualified URL (e.g. ``'http://www.yahoo.com/search/'``) or
|
to. This can be a fully qualified URL
|
||||||
an absolute path with no domain (e.g. ``'/search/'``). Note that this
|
(e.g. ``'http://www.yahoo.com/search/'``) or an absolute path with no
|
||||||
returns an HTTP status code 302.
|
domain (e.g. ``'/search/'``). See :class:`HttpResponse` for other optional
|
||||||
|
constructor arguments. Note that this returns an HTTP status code 302.
|
||||||
|
|
||||||
.. class:: HttpResponsePermanentRedirect
|
.. class:: HttpResponsePermanentRedirect
|
||||||
|
|
||||||
|
@ -743,8 +744,9 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
|
||||||
|
|
||||||
.. class:: HttpResponseNotModified
|
.. class:: HttpResponseNotModified
|
||||||
|
|
||||||
The constructor doesn't take any arguments. Use this to designate that a
|
The constructor doesn't take any arguments and no content should be added
|
||||||
page hasn't been modified since the user's last request (status code 304).
|
to this response. Use this to designate that a page hasn't been modified
|
||||||
|
since the user's last request (status code 304).
|
||||||
|
|
||||||
.. class:: HttpResponseBadRequest
|
.. class:: HttpResponseBadRequest
|
||||||
|
|
||||||
|
@ -760,8 +762,9 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
|
||||||
|
|
||||||
.. class:: HttpResponseNotAllowed
|
.. class:: HttpResponseNotAllowed
|
||||||
|
|
||||||
Like :class:`HttpResponse`, but uses a 405 status code. Takes a single,
|
Like :class:`HttpResponse`, but uses a 405 status code. The first argument
|
||||||
required argument: a list of permitted methods (e.g. ``['GET', 'POST']``).
|
to the constructor is required: a list of permitted methods (e.g.
|
||||||
|
``['GET', 'POST']``).
|
||||||
|
|
||||||
.. class:: HttpResponseGone
|
.. class:: HttpResponseGone
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ compose a prefix, version and key into a final cache key. The default
|
||||||
implementation is equivalent to the function::
|
implementation is equivalent to the function::
|
||||||
|
|
||||||
def make_key(key, key_prefix, version):
|
def make_key(key, key_prefix, version):
|
||||||
return ':'.join([key_prefix, str(version), smart_bytes(key)])
|
return ':'.join([key_prefix, str(version), key])
|
||||||
|
|
||||||
You may use any key function you want, as long as it has the same
|
You may use any key function you want, as long as it has the same
|
||||||
argument signature.
|
argument signature.
|
||||||
|
@ -1375,8 +1375,8 @@ MEDIA_ROOT
|
||||||
|
|
||||||
Default: ``''`` (Empty string)
|
Default: ``''`` (Empty string)
|
||||||
|
|
||||||
Absolute path to the directory that holds media for this installation, used
|
Absolute filesystem path to the directory that will hold :doc:`user-uploaded
|
||||||
for :doc:`managing stored files </topics/files>`.
|
files </topics/files>`.
|
||||||
|
|
||||||
Example: ``"/var/www/example.com/media/"``
|
Example: ``"/var/www/example.com/media/"``
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,10 @@ dot in a variable name, it tries the following lookups, in this order:
|
||||||
* Attribute lookup. Example: ``foo.bar``
|
* Attribute lookup. Example: ``foo.bar``
|
||||||
* List-index lookup. Example: ``foo[bar]``
|
* List-index lookup. Example: ``foo[bar]``
|
||||||
|
|
||||||
|
Note that "bar" in a template expression like ``{{ foo.bar }}`` will be
|
||||||
|
interpreted as a literal string and not using the value of the variable "bar",
|
||||||
|
if one exists in the template context.
|
||||||
|
|
||||||
The template system uses the first lookup type that works. It's short-circuit
|
The template system uses the first lookup type that works. It's short-circuit
|
||||||
logic. Here are a few examples::
|
logic. Here are a few examples::
|
||||||
|
|
||||||
|
@ -424,6 +428,10 @@ optional, third positional argument, ``processors``. In this example, the
|
||||||
my_data_dictionary,
|
my_data_dictionary,
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
Alternatively, use the :meth:`~django.shortcuts.render()` shortcut which is
|
||||||
|
the same as a call to :func:`~django.shortcuts.render_to_response()` with a
|
||||||
|
context_instance argument that forces the use of a ``RequestContext``.
|
||||||
|
|
||||||
Here's what each of the default processors does:
|
Here's what each of the default processors does:
|
||||||
|
|
||||||
django.contrib.auth.context_processors.auth
|
django.contrib.auth.context_processors.auth
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
==========================
|
||||||
|
Django 1.3.2 release notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
*July 30, 2012*
|
||||||
|
|
||||||
|
This is the second security release in the Django 1.3 series, fixing several
|
||||||
|
security issues in Django 1.3. Django 1.3.2 is a recommended upgrade for
|
||||||
|
all users of Django 1.3.
|
||||||
|
|
||||||
|
For a full list of issues addressed in this release, see the `security
|
||||||
|
advisory`_.
|
||||||
|
|
||||||
|
.. _security advisory: https://www.djangoproject.com/weblog/2012/jul/30/security-releases-issued/
|
|
@ -587,7 +587,7 @@ gettext domain):
|
||||||
ones listed later.
|
ones listed later.
|
||||||
|
|
||||||
* The ``locale`` subdirectory of the directory containing the settings, that
|
* The ``locale`` subdirectory of the directory containing the settings, that
|
||||||
usually coincides with and is know as the *project directory* is being
|
usually coincides with and is known as the *project directory* is being
|
||||||
deprecated in this release as a source of translations. (the precedence of
|
deprecated in this release as a source of translations. (the precedence of
|
||||||
these translations is intermediate between applications and :setting:`LOCALE_PATHS`
|
these translations is intermediate between applications and :setting:`LOCALE_PATHS`
|
||||||
translations). See the `corresponding deprecated features section`_
|
translations). See the `corresponding deprecated features section`_
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
==========================
|
||||||
|
Django 1.4.1 release notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
*July 30, 2012*
|
||||||
|
|
||||||
|
This is the first security release in the Django 1.4 series, fixing several
|
||||||
|
security issues in Django 1.4. Django 1.4.1 is a recommended upgrade for
|
||||||
|
all users of Django 1.4.
|
||||||
|
|
||||||
|
For a full list of issues addressed in this release, see the `security
|
||||||
|
advisory`_.
|
||||||
|
|
||||||
|
.. _security advisory: https://www.djangoproject.com/weblog/2012/jul/30/security-releases-issued/
|
|
@ -0,0 +1,14 @@
|
||||||
|
==========================
|
||||||
|
Django 1.4.2 release notes
|
||||||
|
==========================
|
||||||
|
|
||||||
|
*TO BE RELEASED*
|
||||||
|
|
||||||
|
This is the second security release in the Django 1.4 series.
|
||||||
|
|
||||||
|
Backwards incompatible changes
|
||||||
|
==============================
|
||||||
|
|
||||||
|
* The newly introduced :class:`~django.db.models.GenericIPAddressField`
|
||||||
|
constructor arguments have been adapted to match those of all other model
|
||||||
|
fields. The first two keyword arguments are now verbose_name and name.
|
|
@ -172,6 +172,54 @@ If you were using the ``data`` parameter in a PUT request without a
|
||||||
``content_type``, you must encode your data before passing it to the test
|
``content_type``, you must encode your data before passing it to the test
|
||||||
client and set the ``content_type`` argument.
|
client and set the ``content_type`` argument.
|
||||||
|
|
||||||
|
.. _simplejson-incompatibilities:
|
||||||
|
|
||||||
|
System version of :mod:`simplejson` no longer used
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
:ref:`As explained below <simplejson-deprecation>`, Django 1.5 deprecates
|
||||||
|
:mod:`django.utils.simplejson` in favor of Python 2.6's built-in :mod:`json`
|
||||||
|
module. In theory, this change is harmless. Unfortunately, because of
|
||||||
|
incompatibilities between versions of :mod:`simplejson`, it may trigger errors
|
||||||
|
in some circumstances.
|
||||||
|
|
||||||
|
JSON-related features in Django 1.4 always used :mod:`django.utils.simplejson`.
|
||||||
|
This module was actually:
|
||||||
|
|
||||||
|
- A system version of :mod:`simplejson`, if one was available (ie. ``import
|
||||||
|
simplejson`` works), if it was more recent than Django's built-in copy or it
|
||||||
|
had the C speedups, or
|
||||||
|
- The :mod:`json` module from the standard library, if it was available (ie.
|
||||||
|
Python 2.6 or greater), or
|
||||||
|
- A built-in copy of version 2.0.7 of :mod:`simplejson`.
|
||||||
|
|
||||||
|
In Django 1.5, those features use Python's :mod:`json` module, which is based
|
||||||
|
on version 2.0.9 of :mod:`simplejson`.
|
||||||
|
|
||||||
|
There are no known incompatibilities between Django's copy of version 2.0.7 and
|
||||||
|
Python's copy of version 2.0.9. However, there are some incompatibilities
|
||||||
|
between other versions of :mod:`simplejson`:
|
||||||
|
|
||||||
|
- While the :mod:`simplejson` API is documented as always returning unicode
|
||||||
|
strings, the optional C implementation can return a byte string. This was
|
||||||
|
fixed in Python 2.7.
|
||||||
|
- :class:`simplejson.JSONEncoder` gained a ``namedtuple_as_object`` keyword
|
||||||
|
argument in version 2.2.
|
||||||
|
|
||||||
|
More information on these incompatibilities is available in `ticket #18023`_.
|
||||||
|
|
||||||
|
The net result is that, if you have installed :mod:`simplejson` and your code
|
||||||
|
uses Django's serialization internals directly -- for instance
|
||||||
|
:class:`django.core.serializers.json.DjangoJSONEncoder`, the switch from
|
||||||
|
:mod:`simplejson` to :mod:`json` could break your code. (In general, changes to
|
||||||
|
internals aren't documented; we're making an exception here.)
|
||||||
|
|
||||||
|
At this point, the maintainers of Django believe that using :mod:`json` from
|
||||||
|
the standard library offers the strongest guarantee of backwards-compatibility.
|
||||||
|
They recommend to use it from now on.
|
||||||
|
|
||||||
|
.. _ticket #18023: https://code.djangoproject.com/ticket/18023#comment:10
|
||||||
|
|
||||||
String types of hasher method parameters
|
String types of hasher method parameters
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -179,7 +227,7 @@ If you have written a :ref:`custom password hasher <auth_password_storage>`,
|
||||||
your ``encode()``, ``verify()`` or ``safe_summary()`` methods should accept
|
your ``encode()``, ``verify()`` or ``safe_summary()`` methods should accept
|
||||||
Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the
|
Unicode parameters (``password``, ``salt`` or ``encoded``). If any of the
|
||||||
hashing methods need byte strings, you can use the
|
hashing methods need byte strings, you can use the
|
||||||
:func:`~django.utils.encoding.smart_bytes` utility to encode the strings.
|
:func:`~django.utils.encoding.force_bytes` utility to encode the strings.
|
||||||
|
|
||||||
Validation of previous_page_number and next_page_number
|
Validation of previous_page_number and next_page_number
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -282,13 +330,21 @@ Miscellaneous
|
||||||
Features deprecated in 1.5
|
Features deprecated in 1.5
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
.. _simplejson-deprecation:
|
||||||
|
|
||||||
``django.utils.simplejson``
|
``django.utils.simplejson``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Since Django 1.5 drops support for Python 2.5, we can now rely on the
|
Since Django 1.5 drops support for Python 2.5, we can now rely on the
|
||||||
:mod:`json` module being in Python's standard library -- so we've removed
|
:mod:`json` module being available in Python's standard library, so we've
|
||||||
our own copy of ``simplejson``. You can safely change any use of
|
removed our own copy of :mod:`simplejson`. You should now import :mod:`json`
|
||||||
:mod:`django.utils.simplejson` to :mod:`json`.
|
instead :mod:`django.utils.simplejson`.
|
||||||
|
|
||||||
|
Unfortunately, this change might have unwanted side-effects, because of
|
||||||
|
incompatibilities between versions of :mod:`simplejson` -- see the
|
||||||
|
:ref:`backwards-incompatible changes <simplejson-incompatibilities>` section.
|
||||||
|
If you rely on features added to :mod:`simplejson` after it became Python's
|
||||||
|
:mod:`json`, you should import :mod:`simplejson` explicitly.
|
||||||
|
|
||||||
``itercompat.product``
|
``itercompat.product``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -27,6 +27,8 @@ Final releases
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
.. 1.4.2 (uncomment on release)
|
||||||
|
1.4.1
|
||||||
1.4
|
1.4
|
||||||
|
|
||||||
1.3 release
|
1.3 release
|
||||||
|
@ -34,6 +36,7 @@ Final releases
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
1.3.2
|
||||||
1.3.1
|
1.3.1
|
||||||
1.3
|
1.3
|
||||||
|
|
||||||
|
|
|
@ -460,7 +460,7 @@ algorithm.
|
||||||
Increasing the work factor
|
Increasing the work factor
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The PDKDF2 and bcrypt algorithms use a number of iterations or rounds of
|
The PBKDF2 and bcrypt algorithms use a number of iterations or rounds of
|
||||||
hashing. This deliberately slows down attackers, making attacks against hashed
|
hashing. This deliberately slows down attackers, making attacks against hashed
|
||||||
passwords harder. However, as computing power increases, the number of
|
passwords harder. However, as computing power increases, the number of
|
||||||
iterations needs to be increased. We've chosen a reasonable default (and will
|
iterations needs to be increased. We've chosen a reasonable default (and will
|
||||||
|
@ -468,7 +468,7 @@ increase it with each release of Django), but you may wish to tune it up or
|
||||||
down, depending on your security needs and available processing power. To do so,
|
down, depending on your security needs and available processing power. To do so,
|
||||||
you'll subclass the appropriate algorithm and override the ``iterations``
|
you'll subclass the appropriate algorithm and override the ``iterations``
|
||||||
parameters. For example, to increase the number of iterations used by the
|
parameters. For example, to increase the number of iterations used by the
|
||||||
default PDKDF2 algorithm:
|
default PBKDF2 algorithm:
|
||||||
|
|
||||||
1. Create a subclass of ``django.contrib.auth.hashers.PBKDF2PasswordHasher``::
|
1. Create a subclass of ``django.contrib.auth.hashers.PBKDF2PasswordHasher``::
|
||||||
|
|
||||||
|
@ -1170,24 +1170,25 @@ includes a few other useful built-in views located in
|
||||||
:file:`registration/password_reset_form.html` if not supplied.
|
:file:`registration/password_reset_form.html` if not supplied.
|
||||||
|
|
||||||
* ``email_template_name``: The full name of a template to use for
|
* ``email_template_name``: The full name of a template to use for
|
||||||
generating the email with the new password. Defaults to
|
generating the email with the reset password link. Defaults to
|
||||||
:file:`registration/password_reset_email.html` if not supplied.
|
:file:`registration/password_reset_email.html` if not supplied.
|
||||||
|
|
||||||
* ``subject_template_name``: The full name of a template to use for
|
* ``subject_template_name``: The full name of a template to use for
|
||||||
the subject of the email with the new password. Defaults
|
the subject of the email with the reset password link. Defaults
|
||||||
to :file:`registration/password_reset_subject.txt` if not supplied.
|
to :file:`registration/password_reset_subject.txt` if not supplied.
|
||||||
|
|
||||||
.. versionadded:: 1.4
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
* ``password_reset_form``: Form that will be used to set the password.
|
* ``password_reset_form``: Form that will be used to get the email of
|
||||||
Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
|
the user to reset the password for. Defaults to
|
||||||
|
:class:`~django.contrib.auth.forms.PasswordResetForm`.
|
||||||
|
|
||||||
* ``token_generator``: Instance of the class to check the password. This
|
* ``token_generator``: Instance of the class to check the one time link.
|
||||||
will default to ``default_token_generator``, it's an instance of
|
This will default to ``default_token_generator``, it's an instance of
|
||||||
``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
|
``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
|
||||||
|
|
||||||
* ``post_reset_redirect``: The URL to redirect to after a successful
|
* ``post_reset_redirect``: The URL to redirect to after a successful
|
||||||
password change.
|
password reset request.
|
||||||
|
|
||||||
* ``from_email``: A valid email address. By default Django uses
|
* ``from_email``: A valid email address. By default Django uses
|
||||||
the :setting:`DEFAULT_FROM_EMAIL`.
|
the :setting:`DEFAULT_FROM_EMAIL`.
|
||||||
|
@ -1218,7 +1219,7 @@ includes a few other useful built-in views located in
|
||||||
|
|
||||||
* ``uid``: The user's id encoded in base 36.
|
* ``uid``: The user's id encoded in base 36.
|
||||||
|
|
||||||
* ``token``: Token to check that the password is valid.
|
* ``token``: Token to check that the reset link is valid.
|
||||||
|
|
||||||
Sample ``registration/password_reset_email.html`` (email body template):
|
Sample ``registration/password_reset_email.html`` (email body template):
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue