Merge branch 'master' into schema-alteration
This commit is contained in:
commit
b546e7eb63
2
AUTHORS
2
AUTHORS
|
@ -373,6 +373,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
michael.mcewan@gmail.com
|
michael.mcewan@gmail.com
|
||||||
Paul McLanahan <paul@mclanahan.net>
|
Paul McLanahan <paul@mclanahan.net>
|
||||||
Tobias McNulty <http://www.caktusgroup.com/blog>
|
Tobias McNulty <http://www.caktusgroup.com/blog>
|
||||||
|
Andrews Medina <andrewsmedina@gmail.com>
|
||||||
Zain Memon
|
Zain Memon
|
||||||
Christian Metts
|
Christian Metts
|
||||||
michal@plovarna.cz
|
michal@plovarna.cz
|
||||||
|
@ -467,6 +468,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
Vinay Sajip <vinay_sajip@yahoo.co.uk>
|
||||||
Bartolome Sanchez Salado <i42sasab@uco.es>
|
Bartolome Sanchez Salado <i42sasab@uco.es>
|
||||||
Kadesarin Sanjek
|
Kadesarin Sanjek
|
||||||
|
Tim Saylor <tim.saylor@gmail.com>
|
||||||
Massimo Scamarcia <massimo.scamarcia@gmail.com>
|
Massimo Scamarcia <massimo.scamarcia@gmail.com>
|
||||||
Paulo Scardine <paulo@scardine.com.br>
|
Paulo Scardine <paulo@scardine.com.br>
|
||||||
David Schein
|
David Schein
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
include README
|
include README.rst
|
||||||
include AUTHORS
|
include AUTHORS
|
||||||
include INSTALL
|
include INSTALL
|
||||||
include LICENSE
|
include LICENSE
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# This works exactly like 2to3, except that it uses Django's fixers rather
|
||||||
|
# than 2to3's built-in fixers.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from lib2to3.main import main
|
||||||
|
|
||||||
|
sys.exit(main("django.utils.2to3_fixes"))
|
||||||
|
|
|
@ -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.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.contrib.auth.models import User
|
||||||
from django.contrib.admin.util import quote
|
from django.contrib.admin.util import quote
|
||||||
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 smart_text
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
ADDITION = 1
|
ADDITION = 1
|
||||||
CHANGE = 2
|
CHANGE = 2
|
||||||
|
@ -16,6 +17,7 @@ class LogEntryManager(models.Manager):
|
||||||
e = self.model(None, None, user_id, content_type_id, smart_text(object_id), object_repr[:200], action_flag, change_message)
|
e = self.model(None, None, user_id, content_type_id, smart_text(object_id), object_repr[:200], action_flag, change_message)
|
||||||
e.save()
|
e.save()
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class LogEntry(models.Model):
|
class LogEntry(models.Model):
|
||||||
action_time = models.DateTimeField(_('action time'), auto_now=True)
|
action_time = models.DateTimeField(_('action time'), auto_now=True)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
|
@ -36,7 +38,7 @@ class LogEntry(models.Model):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_text(self.action_time)
|
return smart_text(self.action_time)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
if self.action_flag == ADDITION:
|
if self.action_flag == ADDITION:
|
||||||
return _('Added "%(object)s".') % {'object': self.object_repr}
|
return _('Added "%(object)s".') % {'object': self.object_repr}
|
||||||
elif self.action_flag == CHANGE:
|
elif self.action_flag == CHANGE:
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -17,7 +17,7 @@ class AdminLogNode(template.Node):
|
||||||
user_id = self.user
|
user_id = self.user
|
||||||
if not user_id.isdigit():
|
if not user_id.isdigit():
|
||||||
user_id = context[self.user].id
|
user_id = context[self.user].id
|
||||||
context[self.varname] = LogEntry.objects.filter(user__id__exact=user_id).select_related('content_type', 'user')[:self.limit]
|
context[self.varname] = LogEntry.objects.filter(user__id__exact=user_id).select_related('content_type', 'user')[:int(self.limit)]
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@register.tag
|
@register.tag
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -148,7 +148,7 @@ class ChangeList(object):
|
||||||
if remove is None: remove = []
|
if remove is None: remove = []
|
||||||
p = self.params.copy()
|
p = self.params.copy()
|
||||||
for r in remove:
|
for r in remove:
|
||||||
for k in p.keys():
|
for k in list(p):
|
||||||
if k.startswith(r):
|
if k.startswith(r):
|
||||||
del p[k]
|
del p[k]
|
||||||
for k, v in new_params.items():
|
for k, v in new_params.items():
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -7,6 +7,7 @@ from django.conf import settings
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.utils.decorators import available_attrs
|
from django.utils.decorators import available_attrs
|
||||||
|
from django.utils.encoding import force_str
|
||||||
|
|
||||||
|
|
||||||
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
||||||
|
@ -22,9 +23,11 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
|
||||||
if test_func(request.user):
|
if test_func(request.user):
|
||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
path = request.build_absolute_uri()
|
path = request.build_absolute_uri()
|
||||||
|
# urlparse chokes on lazy objects in Python 3
|
||||||
|
login_url_as_str = force_str(login_url or settings.LOGIN_URL)
|
||||||
# If the login url is the same scheme and net location then just
|
# If the login url is the same scheme and net location then just
|
||||||
# use the path as the "next" url.
|
# use the path as the "next" url.
|
||||||
login_scheme, login_netloc = urlparse(login_url or settings.LOGIN_URL)[:2]
|
login_scheme, login_netloc = urlparse(login_url_as_str)[:2]
|
||||||
current_scheme, current_netloc = urlparse(path)[:2]
|
current_scheme, current_netloc = urlparse(path)[:2]
|
||||||
if ((not login_scheme or login_scheme == current_scheme) and
|
if ((not login_scheme or login_scheme == current_scheme) and
|
||||||
(not login_netloc or login_netloc == current_netloc)):
|
(not login_netloc or login_netloc == current_netloc)):
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -219,7 +219,7 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
|
||||||
if not iterations:
|
if not iterations:
|
||||||
iterations = self.iterations
|
iterations = self.iterations
|
||||||
hash = pbkdf2(password, salt, iterations, digest=self.digest)
|
hash = pbkdf2(password, salt, iterations, digest=self.digest)
|
||||||
hash = base64.b64encode(hash).strip()
|
hash = base64.b64encode(hash).decode('ascii').strip()
|
||||||
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
|
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
|
||||||
|
|
||||||
def verify(self, password, encoded):
|
def verify(self, password, encoded):
|
||||||
|
@ -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, '')
|
||||||
|
|
|
@ -9,6 +9,7 @@ import unicodedata
|
||||||
from django.contrib.auth import models as auth_app
|
from django.contrib.auth import models as auth_app
|
||||||
from django.db.models import get_models, signals
|
from django.db.models import get_models, signals
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import six
|
||||||
from django.utils.six.moves import input
|
from django.utils.six.moves import input
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,13 +86,22 @@ def get_system_username():
|
||||||
username could not be determined.
|
username could not be determined.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return getpass.getuser().decode(locale.getdefaultlocale()[1])
|
result = getpass.getuser()
|
||||||
except (ImportError, KeyError, UnicodeDecodeError):
|
except (ImportError, KeyError):
|
||||||
# KeyError will be raised by os.getpwuid() (called by getuser())
|
# KeyError will be raised by os.getpwuid() (called by getuser())
|
||||||
# if there is no corresponding entry in the /etc/passwd file
|
# if there is no corresponding entry in the /etc/passwd file
|
||||||
# (a very restricted chroot environment, for example).
|
# (a very restricted chroot environment, for example).
|
||||||
|
return ''
|
||||||
|
if not six.PY3:
|
||||||
|
default_locale = locale.getdefaultlocale()[1]
|
||||||
|
if not default_locale:
|
||||||
|
return ''
|
||||||
|
try:
|
||||||
|
result = result.decode(default_locale)
|
||||||
|
except UnicodeDecodeError:
|
||||||
# UnicodeDecodeError - preventive treatment for non-latin Windows.
|
# UnicodeDecodeError - preventive treatment for non-latin Windows.
|
||||||
return ''
|
return ''
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_default_username(check_db=True):
|
def get_default_username(check_db=True):
|
||||||
|
@ -108,7 +118,7 @@ def get_default_username(check_db=True):
|
||||||
default_username = get_system_username()
|
default_username = get_system_username()
|
||||||
try:
|
try:
|
||||||
default_username = unicodedata.normalize('NFKD', default_username)\
|
default_username = unicodedata.normalize('NFKD', default_username)\
|
||||||
.encode('ascii', 'ignore').replace(' ', '').lower()
|
.encode('ascii', 'ignore').decode('ascii').replace(' ', '').lower()
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
return ''
|
return ''
|
||||||
if not RE_VALID_USERNAME.match(default_username):
|
if not RE_VALID_USERNAME.match(default_username):
|
||||||
|
|
|
@ -16,6 +16,7 @@ from django.contrib.auth.hashers import (
|
||||||
check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
|
check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
|
||||||
from django.contrib.auth.signals import user_logged_in
|
from django.contrib.auth.signals import user_logged_in
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
def update_last_login(sender, user, **kwargs):
|
def update_last_login(sender, user, **kwargs):
|
||||||
|
@ -41,6 +42,7 @@ class PermissionManager(models.Manager):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Permission(models.Model):
|
class Permission(models.Model):
|
||||||
"""
|
"""
|
||||||
The permissions system provides a way to assign permissions to specific
|
The permissions system provides a way to assign permissions to specific
|
||||||
|
@ -76,7 +78,7 @@ class Permission(models.Model):
|
||||||
ordering = ('content_type__app_label', 'content_type__model',
|
ordering = ('content_type__app_label', 'content_type__model',
|
||||||
'codename')
|
'codename')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s | %s | %s" % (
|
return "%s | %s | %s" % (
|
||||||
six.text_type(self.content_type.app_label),
|
six.text_type(self.content_type.app_label),
|
||||||
six.text_type(self.content_type),
|
six.text_type(self.content_type),
|
||||||
|
@ -94,6 +96,7 @@ class GroupManager(models.Manager):
|
||||||
def get_by_natural_key(self, name):
|
def get_by_natural_key(self, name):
|
||||||
return self.get(name=name)
|
return self.get(name=name)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Group(models.Model):
|
class Group(models.Model):
|
||||||
"""
|
"""
|
||||||
Groups are a generic way of categorizing users to apply permissions, or
|
Groups are a generic way of categorizing users to apply permissions, or
|
||||||
|
@ -121,7 +124,7 @@ class Group(models.Model):
|
||||||
verbose_name = _('group')
|
verbose_name = _('group')
|
||||||
verbose_name_plural = _('groups')
|
verbose_name_plural = _('groups')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def natural_key(self):
|
def natural_key(self):
|
||||||
|
@ -221,6 +224,7 @@ def _user_has_module_perms(user, app_label):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class User(models.Model):
|
class User(models.Model):
|
||||||
"""
|
"""
|
||||||
Users within the Django authentication system are represented by this
|
Users within the Django authentication system are represented by this
|
||||||
|
@ -259,7 +263,7 @@ class User(models.Model):
|
||||||
verbose_name = _('user')
|
verbose_name = _('user')
|
||||||
verbose_name_plural = _('users')
|
verbose_name_plural = _('users')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
def natural_key(self):
|
def natural_key(self):
|
||||||
|
@ -403,6 +407,7 @@ class User(models.Model):
|
||||||
return self._profile_cache
|
return self._profile_cache
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class AnonymousUser(object):
|
class AnonymousUser(object):
|
||||||
id = None
|
id = None
|
||||||
pk = None
|
pk = None
|
||||||
|
@ -416,11 +421,8 @@ class AnonymousUser(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return 'AnonymousUser'
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return six.text_type(self).encode('utf-8')
|
return 'AnonymousUser'
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, self.__class__)
|
return isinstance(other, self.__class__)
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
|
import locale
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from django.contrib.auth.management.commands import createsuperuser
|
||||||
from django.contrib.auth.models import User, AnonymousUser
|
from django.contrib.auth.models import User, AnonymousUser
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
from django.utils.unittest import skipUnless
|
|
||||||
|
|
||||||
try:
|
|
||||||
import crypt as crypt_module
|
|
||||||
except ImportError:
|
|
||||||
crypt_module = None
|
|
||||||
|
|
||||||
|
|
||||||
class BasicTestCase(TestCase):
|
class BasicTestCase(TestCase):
|
||||||
|
@ -111,3 +109,37 @@ class BasicTestCase(TestCase):
|
||||||
u = User.objects.get(username="joe+admin@somewhere.org")
|
u = User.objects.get(username="joe+admin@somewhere.org")
|
||||||
self.assertEqual(u.email, 'joe@somewhere.org')
|
self.assertEqual(u.email, 'joe@somewhere.org')
|
||||||
self.assertFalse(u.has_usable_password())
|
self.assertFalse(u.has_usable_password())
|
||||||
|
|
||||||
|
def test_createsuperuser_nolocale(self):
|
||||||
|
"""
|
||||||
|
Check that createsuperuser does not break when no locale is set. See
|
||||||
|
ticket #16017.
|
||||||
|
"""
|
||||||
|
|
||||||
|
old_getdefaultlocale = locale.getdefaultlocale
|
||||||
|
old_getpass = createsuperuser.getpass
|
||||||
|
try:
|
||||||
|
# Temporarily remove locale information
|
||||||
|
locale.getdefaultlocale = lambda: (None, None)
|
||||||
|
|
||||||
|
# Temporarily replace getpass to allow interactive code to be used
|
||||||
|
# non-interactively
|
||||||
|
class mock_getpass: pass
|
||||||
|
mock_getpass.getpass = staticmethod(lambda p=None: "nopasswd")
|
||||||
|
createsuperuser.getpass = mock_getpass
|
||||||
|
|
||||||
|
# Call the command in this new environment
|
||||||
|
new_io = StringIO()
|
||||||
|
call_command("createsuperuser", interactive=True, username="nolocale@somewhere.org", email="nolocale@somewhere.org", stdout=new_io)
|
||||||
|
|
||||||
|
except TypeError as e:
|
||||||
|
self.fail("createsuperuser fails if the OS provides no information about the current locale")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Re-apply locale and getpass information
|
||||||
|
createsuperuser.getpass = old_getpass
|
||||||
|
locale.getdefaultlocale = old_getdefaultlocale
|
||||||
|
|
||||||
|
# If we were successful, a user should have been created
|
||||||
|
u = User.objects.get(username="nolocale@somewhere.org")
|
||||||
|
self.assertEqual(u.email, 'nolocale@somewhere.org')
|
||||||
|
|
|
@ -4,16 +4,20 @@ from django.contrib.auth import models, management
|
||||||
from django.contrib.auth.management.commands import changepassword
|
from django.contrib.auth.management.commands import changepassword
|
||||||
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.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'
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import sys
|
||||||
from datetime import date, timedelta
|
from datetime import date, timedelta
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils import unittest
|
||||||
|
|
||||||
|
|
||||||
class TokenGeneratorTest(TestCase):
|
class TokenGeneratorTest(TestCase):
|
||||||
|
@ -51,6 +53,7 @@ class TokenGeneratorTest(TestCase):
|
||||||
p2 = Mocked(date.today() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
|
p2 = Mocked(date.today() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
|
||||||
self.assertFalse(p2.check_token(user, tk1))
|
self.assertFalse(p2.check_token(user, tk1))
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.version_info[:2] >= (3, 0), "Unnecessary test with Python 3")
|
||||||
def test_date_length(self):
|
def test_date_length(self):
|
||||||
"""
|
"""
|
||||||
Make sure we don't allow overly long dates, causing a potential DoS.
|
Make sure we don't allow overly long dates, causing a potential DoS.
|
||||||
|
|
|
@ -7,6 +7,7 @@ from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect, QueryDict
|
from django.http import HttpResponseRedirect, QueryDict
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.utils.encoding import force_str
|
||||||
from django.utils.http import base36_to_int
|
from django.utils.http import base36_to_int
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.decorators.debug import sensitive_post_parameters
|
from django.views.decorators.debug import sensitive_post_parameters
|
||||||
|
@ -116,10 +117,10 @@ def redirect_to_login(next, login_url=None,
|
||||||
"""
|
"""
|
||||||
Redirects the user to the login page, passing the given 'next' page
|
Redirects the user to the login page, passing the given 'next' page
|
||||||
"""
|
"""
|
||||||
if not login_url:
|
# urlparse chokes on lazy objects in Python 3
|
||||||
login_url = settings.LOGIN_URL
|
login_url_as_str = force_str(login_url or settings.LOGIN_URL)
|
||||||
|
|
||||||
login_url_parts = list(urlparse(login_url))
|
login_url_parts = list(urlparse(login_url_as_str))
|
||||||
if redirect_field_name:
|
if redirect_field_name:
|
||||||
querystring = QueryDict(login_url_parts[4], mutable=True)
|
querystring = QueryDict(login_url_parts[4], mutable=True)
|
||||||
querystring[redirect_field_name] = next
|
querystring[redirect_field_name] = next
|
||||||
|
@ -200,7 +201,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
|
||||||
try:
|
try:
|
||||||
uid_int = base36_to_int(uidb36)
|
uid_int = base36_to_int(uidb36)
|
||||||
user = User.objects.get(id=uid_int)
|
user = User.objects.get(id=uid_int)
|
||||||
except (ValueError, User.DoesNotExist):
|
except (ValueError, OverflowError, User.DoesNotExist):
|
||||||
user = None
|
user = None
|
||||||
|
|
||||||
if user is not None and token_generator.check_token(user, token):
|
if user is not None and token_generator.check_token(user, token):
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.core import urlresolvers
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH',3000)
|
COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH',3000)
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ class BaseCommentAbstractModel(models.Model):
|
||||||
args=(self.content_type_id, self.object_pk)
|
args=(self.content_type_id, self.object_pk)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Comment(BaseCommentAbstractModel):
|
class Comment(BaseCommentAbstractModel):
|
||||||
"""
|
"""
|
||||||
A user comment about some object.
|
A user comment about some object.
|
||||||
|
@ -76,7 +78,7 @@ class Comment(BaseCommentAbstractModel):
|
||||||
verbose_name = _('comment')
|
verbose_name = _('comment')
|
||||||
verbose_name_plural = _('comments')
|
verbose_name_plural = _('comments')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s: %s..." % (self.name, self.comment[:50])
|
return "%s: %s..." % (self.name, self.comment[:50])
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
@ -153,6 +155,7 @@ class Comment(BaseCommentAbstractModel):
|
||||||
}
|
}
|
||||||
return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % d
|
return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % d
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class CommentFlag(models.Model):
|
class CommentFlag(models.Model):
|
||||||
"""
|
"""
|
||||||
Records a flag on a comment. This is intentionally flexible; right now, a
|
Records a flag on a comment. This is intentionally flexible; right now, a
|
||||||
|
@ -182,7 +185,7 @@ class CommentFlag(models.Model):
|
||||||
verbose_name = _('comment flag')
|
verbose_name = _('comment flag')
|
||||||
verbose_name_plural = _('comment flags')
|
verbose_name_plural = _('comment flags')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s flag of comment ID %s by %s" % \
|
return "%s flag of comment ID %s by %s" % \
|
||||||
(self.flag, self.comment_id, self.user.username)
|
(self.flag, self.comment_id, self.user.username)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_text, force_text
|
from django.utils.encoding import smart_text, force_text
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
class ContentTypeManager(models.Manager):
|
class ContentTypeManager(models.Manager):
|
||||||
|
|
||||||
|
@ -122,6 +123,7 @@ class ContentTypeManager(models.Manager):
|
||||||
self.__class__._cache.setdefault(using, {})[key] = ct
|
self.__class__._cache.setdefault(using, {})[key] = ct
|
||||||
self.__class__._cache.setdefault(using, {})[ct.id] = ct
|
self.__class__._cache.setdefault(using, {})[ct.id] = ct
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class ContentType(models.Model):
|
class ContentType(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
app_label = models.CharField(max_length=100)
|
app_label = models.CharField(max_length=100)
|
||||||
|
@ -135,7 +137,7 @@ class ContentType(models.Model):
|
||||||
ordering = ('name',)
|
ordering = ('name',)
|
||||||
unique_together = (('app_label', 'model'),)
|
unique_together = (('app_label', 'model'),)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
# self.name is deprecated in favor of using model's verbose_name, which
|
# self.name is deprecated in favor of using model's verbose_name, which
|
||||||
# can be translated. Formal deprecation is delayed until we have DB
|
# can be translated. Formal deprecation is delayed until we have DB
|
||||||
# migration to be able to remove the field from the database along with
|
# migration to be able to remove the field from the database along with
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.http import HttpRequest, Http404
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
class ConcreteModel(models.Model):
|
class ConcreteModel(models.Model):
|
||||||
|
@ -17,13 +18,14 @@ class ProxyModel(ConcreteModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class FooWithoutUrl(models.Model):
|
class FooWithoutUrl(models.Model):
|
||||||
"""
|
"""
|
||||||
Fake model not defining ``get_absolute_url`` for
|
Fake model not defining ``get_absolute_url`` for
|
||||||
:meth:`ContentTypesTests.test_shortcut_view_without_get_absolute_url`"""
|
:meth:`ContentTypesTests.test_shortcut_view_without_get_absolute_url`"""
|
||||||
name = models.CharField(max_length=30, unique=True)
|
name = models.CharField(max_length=30, unique=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ 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_bytes, 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
|
||||||
|
|
||||||
EMPTY_VALUE = '(None)'
|
EMPTY_VALUE = '(None)'
|
||||||
DISPLAY_SIZE = 100
|
DISPLAY_SIZE = 100
|
||||||
|
@ -22,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 '<EasyModel for %s>' % smart_bytes(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."
|
||||||
|
@ -61,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_bytes('<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:
|
||||||
|
@ -79,27 +80,25 @@ class EasyChoice(object):
|
||||||
self.value, self.label = value, label
|
self.value, self.label = value, label
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_bytes('<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))
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class EasyInstance(object):
|
class EasyInstance(object):
|
||||||
def __init__(self, easy_model, instance):
|
def __init__(self, easy_model, instance):
|
||||||
self.model, self.instance = easy_model, instance
|
self.model, self.instance = easy_model, instance
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_bytes('<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 __unicode__(self):
|
def __str__(self):
|
||||||
val = smart_text(self.instance)
|
val = smart_text(self.instance)
|
||||||
if len(val) > DISPLAY_SIZE:
|
if len(val) > DISPLAY_SIZE:
|
||||||
return val[:DISPLAY_SIZE] + '...'
|
return val[:DISPLAY_SIZE] + '...'
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.__unicode__().encode('utf-8')
|
|
||||||
|
|
||||||
def pk(self):
|
def pk(self):
|
||||||
return self.instance._get_pk_val()
|
return self.instance._get_pk_val()
|
||||||
|
|
||||||
|
@ -136,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_bytes('<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,26 +1,30 @@
|
||||||
from django.contrib import databrowse
|
from django.contrib import databrowse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SomeModel(models.Model):
|
class SomeModel(models.Model):
|
||||||
some_field = models.CharField(max_length=50)
|
some_field = models.CharField(max_length=50)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.some_field
|
return self.some_field
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SomeOtherModel(models.Model):
|
class SomeOtherModel(models.Model):
|
||||||
some_other_field = models.CharField(max_length=50)
|
some_other_field = models.CharField(max_length=50)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.some_other_field
|
return self.some_other_field
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class YetAnotherModel(models.Model):
|
class YetAnotherModel(models.Model):
|
||||||
yet_another_field = models.CharField(max_length=50)
|
yet_another_field = models.CharField(max_length=50)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.yet_another_field
|
return self.yet_another_field
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,10 @@ from __future__ import unicode_literals
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class FlatPage(models.Model):
|
class FlatPage(models.Model):
|
||||||
url = models.CharField(_('URL'), max_length=100, db_index=True)
|
url = models.CharField(_('URL'), max_length=100, db_index=True)
|
||||||
title = models.CharField(_('title'), max_length=200)
|
title = models.CharField(_('title'), max_length=200)
|
||||||
|
@ -21,7 +23,7 @@ class FlatPage(models.Model):
|
||||||
verbose_name_plural = _('flat pages')
|
verbose_name_plural = _('flat pages')
|
||||||
ordering = ('url',)
|
ordering = ('url',)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s -- %s" % (self.url, self.title)
|
return "%s -- %s" % (self.url, self.title)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
import pickle
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
@ -16,6 +19,7 @@ from django.contrib.formtools.tests.wizard import *
|
||||||
from django.contrib.formtools.tests.forms import *
|
from django.contrib.formtools.tests.forms import *
|
||||||
|
|
||||||
success_string = "Done was called!"
|
success_string = "Done was called!"
|
||||||
|
success_string_encoded = success_string.encode()
|
||||||
|
|
||||||
class TestFormPreview(preview.FormPreview):
|
class TestFormPreview(preview.FormPreview):
|
||||||
def get_context(self, request, form):
|
def get_context(self, request, form):
|
||||||
|
@ -78,7 +82,7 @@ class PreviewTests(TestCase):
|
||||||
"""
|
"""
|
||||||
# Pass strings for form submittal and add stage variable to
|
# Pass strings for form submittal and add stage variable to
|
||||||
# show we previously saw first stage of the form.
|
# show we previously saw first stage of the form.
|
||||||
self.test_data.update({'stage': 1})
|
self.test_data.update({'stage': 1, 'date1': datetime.date(2006, 10, 25)})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
# Check to confirm stage is set to 2 in output form.
|
# Check to confirm stage is set to 2 in output form.
|
||||||
stage = self.input % 2
|
stage = self.input % 2
|
||||||
|
@ -96,13 +100,13 @@ class PreviewTests(TestCase):
|
||||||
"""
|
"""
|
||||||
# Pass strings for form submittal and add stage variable to
|
# Pass strings for form submittal and add stage variable to
|
||||||
# show we previously saw first stage of the form.
|
# show we previously saw first stage of the form.
|
||||||
self.test_data.update({'stage':2})
|
self.test_data.update({'stage': 2, 'date1': datetime.date(2006, 10, 25)})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertNotEqual(response.content, success_string)
|
self.assertNotEqual(response.content, success_string_encoded)
|
||||||
hash = self.preview.security_hash(None, TestForm(self.test_data))
|
hash = self.preview.security_hash(None, TestForm(self.test_data))
|
||||||
self.test_data.update({'hash': hash})
|
self.test_data.update({'hash': hash})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertEqual(response.content, success_string)
|
self.assertEqual(response.content, success_string_encoded)
|
||||||
|
|
||||||
def test_bool_submit(self):
|
def test_bool_submit(self):
|
||||||
"""
|
"""
|
||||||
|
@ -122,7 +126,7 @@ class PreviewTests(TestCase):
|
||||||
self.test_data.update({'hash': hash, 'bool1': 'False'})
|
self.test_data.update({'hash': hash, 'bool1': 'False'})
|
||||||
with warnings.catch_warnings(record=True):
|
with warnings.catch_warnings(record=True):
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertEqual(response.content, success_string)
|
self.assertEqual(response.content, success_string_encoded)
|
||||||
|
|
||||||
def test_form_submit_good_hash(self):
|
def test_form_submit_good_hash(self):
|
||||||
"""
|
"""
|
||||||
|
@ -133,11 +137,11 @@ class PreviewTests(TestCase):
|
||||||
# show we previously saw first stage of the form.
|
# show we previously saw first stage of the form.
|
||||||
self.test_data.update({'stage':2})
|
self.test_data.update({'stage':2})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertNotEqual(response.content, success_string)
|
self.assertNotEqual(response.content, success_string_encoded)
|
||||||
hash = utils.form_hmac(TestForm(self.test_data))
|
hash = utils.form_hmac(TestForm(self.test_data))
|
||||||
self.test_data.update({'hash': hash})
|
self.test_data.update({'hash': hash})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertEqual(response.content, success_string)
|
self.assertEqual(response.content, success_string_encoded)
|
||||||
|
|
||||||
|
|
||||||
def test_form_submit_bad_hash(self):
|
def test_form_submit_bad_hash(self):
|
||||||
|
@ -150,11 +154,11 @@ class PreviewTests(TestCase):
|
||||||
self.test_data.update({'stage':2})
|
self.test_data.update({'stage':2})
|
||||||
response = self.client.post('/preview/', self.test_data)
|
response = self.client.post('/preview/', self.test_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertNotEqual(response.content, success_string)
|
self.assertNotEqual(response.content, success_string_encoded)
|
||||||
hash = utils.form_hmac(TestForm(self.test_data)) + "bad"
|
hash = utils.form_hmac(TestForm(self.test_data)) + "bad"
|
||||||
self.test_data.update({'hash': hash})
|
self.test_data.update({'hash': hash})
|
||||||
response = self.client.post('/previewpreview/', self.test_data)
|
response = self.client.post('/previewpreview/', self.test_data)
|
||||||
self.assertNotEqual(response.content, success_string)
|
self.assertNotEqual(response.content, success_string_encoded)
|
||||||
|
|
||||||
|
|
||||||
class FormHmacTests(unittest.TestCase):
|
class FormHmacTests(unittest.TestCase):
|
||||||
|
@ -165,8 +169,8 @@ class FormHmacTests(unittest.TestCase):
|
||||||
leading/trailing whitespace so as to be friendly to broken browsers that
|
leading/trailing whitespace so as to be friendly to broken browsers that
|
||||||
submit it (usually in textareas).
|
submit it (usually in textareas).
|
||||||
"""
|
"""
|
||||||
f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
|
f1 = HashTestForm({'name': 'joe', 'bio': 'Speaking español.'})
|
||||||
f2 = HashTestForm({'name': ' joe', 'bio': 'Nothing notable. '})
|
f2 = HashTestForm({'name': ' joe', 'bio': 'Speaking español. '})
|
||||||
hash1 = utils.form_hmac(f1)
|
hash1 = utils.form_hmac(f1)
|
||||||
hash2 = utils.form_hmac(f2)
|
hash2 = utils.form_hmac(f2)
|
||||||
self.assertEqual(hash1, hash2)
|
self.assertEqual(hash1, hash2)
|
||||||
|
@ -270,7 +274,10 @@ class WizardTests(TestCase):
|
||||||
"""
|
"""
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "1"}
|
"wizard_step": "1"}
|
||||||
response = self.client.post('/wizard1/', data)
|
response = self.client.post('/wizard1/', data)
|
||||||
self.assertEqual(2, response.context['step0'])
|
self.assertEqual(2, response.context['step0'])
|
||||||
|
@ -295,15 +302,24 @@ class WizardTests(TestCase):
|
||||||
wizard = WizardWithProcessStep([WizardPageOneForm])
|
wizard = WizardWithProcessStep([WizardPageOneForm])
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "1"}
|
"wizard_step": "1"}
|
||||||
wizard(DummyRequest(POST=data))
|
wizard(DummyRequest(POST=data))
|
||||||
self.assertTrue(reached[0])
|
self.assertTrue(reached[0])
|
||||||
|
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
"hash_1": "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
|
"hash_1": {
|
||||||
|
2: "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
|
||||||
|
3: "c33142ef9d01b1beae238adf22c3c6c57328f51a",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "2"}
|
"wizard_step": "2"}
|
||||||
self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
|
self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
|
||||||
|
|
||||||
|
@ -325,7 +341,10 @@ class WizardTests(TestCase):
|
||||||
WizardPageThreeForm])
|
WizardPageThreeForm])
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "1"}
|
"wizard_step": "1"}
|
||||||
wizard(DummyRequest(POST=data))
|
wizard(DummyRequest(POST=data))
|
||||||
self.assertTrue(reached[0])
|
self.assertTrue(reached[0])
|
||||||
|
@ -349,7 +368,10 @@ class WizardTests(TestCase):
|
||||||
|
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "1"}
|
"wizard_step": "1"}
|
||||||
wizard(DummyRequest(POST=data))
|
wizard(DummyRequest(POST=data))
|
||||||
self.assertTrue(reached[0])
|
self.assertTrue(reached[0])
|
||||||
|
@ -375,7 +397,10 @@ class WizardTests(TestCase):
|
||||||
WizardPageThreeForm])
|
WizardPageThreeForm])
|
||||||
data = {"0-field": "test",
|
data = {"0-field": "test",
|
||||||
"1-field": "test2",
|
"1-field": "test2",
|
||||||
"hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
"hash_0": {
|
||||||
|
2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
|
||||||
|
3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
|
||||||
|
}[pickle.HIGHEST_PROTOCOL],
|
||||||
"wizard_step": "1"}
|
"wizard_step": "1"}
|
||||||
wizard(DummyRequest(POST=data))
|
wizard(DummyRequest(POST=data))
|
||||||
self.assertTrue(reached[0])
|
self.assertTrue(reached[0])
|
||||||
|
|
|
@ -21,6 +21,7 @@ class TestForm(forms.Form):
|
||||||
field1 = forms.CharField()
|
field1 = forms.CharField()
|
||||||
field1_ = forms.CharField()
|
field1_ = forms.CharField()
|
||||||
bool1 = forms.BooleanField(required=False)
|
bool1 = forms.BooleanField(required=False)
|
||||||
|
date1 = forms.DateField(required=False)
|
||||||
|
|
||||||
class HashTestForm(forms.Form):
|
class HashTestForm(forms.Form):
|
||||||
name = forms.CharField()
|
name = forms.CharField()
|
||||||
|
|
|
@ -122,6 +122,7 @@ class NamedWizardTests(object):
|
||||||
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
||||||
|
|
||||||
post_data = self.wizard_step_data[1]
|
post_data = self.wizard_step_data[1]
|
||||||
|
post_data['form2-file1'].close()
|
||||||
post_data['form2-file1'] = open(__file__, 'rb')
|
post_data['form2-file1'] = open(__file__, 'rb')
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse(self.wizard_urlname,
|
reverse(self.wizard_urlname,
|
||||||
|
@ -149,7 +150,9 @@ class NamedWizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
all_data = response.context['form_list']
|
all_data = response.context['form_list']
|
||||||
self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
|
with open(__file__, 'rb') as f:
|
||||||
|
self.assertEqual(all_data[1]['file1'].read(), f.read())
|
||||||
|
all_data[1]['file1'].close()
|
||||||
del all_data[1]['file1']
|
del all_data[1]['file1']
|
||||||
self.assertEqual(all_data, [
|
self.assertEqual(all_data, [
|
||||||
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
|
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
|
||||||
|
@ -182,9 +185,10 @@ class NamedWizardTests(object):
|
||||||
response = self.client.get(step2_url)
|
response = self.client.get(step2_url)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
||||||
|
with open(__file__, 'rb') as f:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response.context['wizard']['form'].files['form2-file1'].read(),
|
response.context['wizard']['form'].files['form2-file1'].read(),
|
||||||
open(__file__, 'rb').read())
|
f.read())
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse(self.wizard_urlname,
|
reverse(self.wizard_urlname,
|
||||||
|
@ -201,7 +205,9 @@ class NamedWizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
all_data = response.context['all_cleaned_data']
|
all_data = response.context['all_cleaned_data']
|
||||||
self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
|
with open(__file__, 'rb') as f:
|
||||||
|
self.assertEqual(all_data['file1'].read(), f.read())
|
||||||
|
all_data['file1'].close()
|
||||||
del all_data['file1']
|
del all_data['file1']
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
all_data,
|
all_data,
|
||||||
|
@ -225,6 +231,7 @@ class NamedWizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
post_data = self.wizard_step_data[1]
|
post_data = self.wizard_step_data[1]
|
||||||
|
post_data['form2-file1'].close()
|
||||||
post_data['form2-file1'] = open(__file__, 'rb')
|
post_data['form2-file1'] = open(__file__, 'rb')
|
||||||
response = self.client.post(
|
response = self.client.post(
|
||||||
reverse(self.wizard_urlname,
|
reverse(self.wizard_urlname,
|
||||||
|
|
|
@ -95,7 +95,9 @@ class WizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
all_data = response.context['form_list']
|
all_data = response.context['form_list']
|
||||||
self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
|
with open(__file__, 'rb') as f:
|
||||||
|
self.assertEqual(all_data[1]['file1'].read(), f.read())
|
||||||
|
all_data[1]['file1'].close()
|
||||||
del all_data[1]['file1']
|
del all_data[1]['file1']
|
||||||
self.assertEqual(all_data, [
|
self.assertEqual(all_data, [
|
||||||
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
|
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
|
||||||
|
@ -112,7 +114,8 @@ class WizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
post_data = self.wizard_step_data[1]
|
post_data = self.wizard_step_data[1]
|
||||||
post_data['form2-file1'] = open(__file__, 'rb')
|
with open(__file__, 'rb') as post_file:
|
||||||
|
post_data['form2-file1'] = post_file
|
||||||
response = self.client.post(self.wizard_url, post_data)
|
response = self.client.post(self.wizard_url, post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
@ -123,7 +126,9 @@ class WizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
all_data = response.context['all_cleaned_data']
|
all_data = response.context['all_cleaned_data']
|
||||||
self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
|
with open(__file__, 'rb') as f:
|
||||||
|
self.assertEqual(all_data['file1'].read(), f.read())
|
||||||
|
all_data['file1'].close()
|
||||||
del all_data['file1']
|
del all_data['file1']
|
||||||
self.assertEqual(all_data, {
|
self.assertEqual(all_data, {
|
||||||
'name': 'Pony', 'thirsty': True, 'user': self.testuser,
|
'name': 'Pony', 'thirsty': True, 'user': self.testuser,
|
||||||
|
@ -140,6 +145,7 @@ class WizardTests(object):
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
post_data = self.wizard_step_data[1]
|
post_data = self.wizard_step_data[1]
|
||||||
|
post_data['form2-file1'].close()
|
||||||
post_data['form2-file1'] = open(__file__, 'rb')
|
post_data['form2-file1'] = open(__file__, 'rb')
|
||||||
response = self.client.post(self.wizard_url, post_data)
|
response = self.client.post(self.wizard_url, post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -167,6 +173,7 @@ class WizardTests(object):
|
||||||
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
|
||||||
|
|
||||||
post_data = self.wizard_step_data[1]
|
post_data = self.wizard_step_data[1]
|
||||||
|
post_data['form2-file1'].close()
|
||||||
post_data['form2-file1'] = open(__file__, 'rb')
|
post_data['form2-file1'] = open(__file__, 'rb')
|
||||||
response = self.client.post(self.wizard_url, post_data)
|
response = self.client.post(self.wizard_url, post_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# Do not try cPickle here (see #18340)
|
# Do not try cPickle here (see #18340)
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from django.core.files.uploadedfile import UploadedFile
|
from django.core.files.uploadedfile import UploadedFile
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.encoding import smart_bytes
|
|
||||||
from django.utils.functional import lazy_property
|
from django.utils.functional import lazy_property
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -74,8 +73,7 @@ class BaseStorage(object):
|
||||||
|
|
||||||
files = {}
|
files = {}
|
||||||
for field, field_dict in six.iteritems(wizard_files):
|
for field, field_dict in six.iteritems(wizard_files):
|
||||||
field_dict = dict((smart_bytes(k), v)
|
field_dict = field_dict.copy()
|
||||||
for k, v in six.iteritems(field_dict))
|
|
||||||
tmp_name = field_dict.pop('tmp_name')
|
tmp_name = field_dict.pop('tmp_name')
|
||||||
files[field] = UploadedFile(
|
files[field] = UploadedFile(
|
||||||
file=self.file_storage.open(tmp_name), **field_dict)
|
file=self.file_storage.open(tmp_name), **field_dict)
|
||||||
|
|
|
@ -5,6 +5,7 @@ Base/mixin classes for the spatial backend database operations and the
|
||||||
import re
|
import re
|
||||||
from django.contrib.gis import gdal
|
from django.contrib.gis import gdal
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
class BaseSpatialOperations(object):
|
class BaseSpatialOperations(object):
|
||||||
"""
|
"""
|
||||||
|
@ -131,6 +132,7 @@ class BaseSpatialOperations(object):
|
||||||
def spatial_ref_sys(self):
|
def spatial_ref_sys(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SpatialRefSysMixin(object):
|
class SpatialRefSysMixin(object):
|
||||||
"""
|
"""
|
||||||
The SpatialRefSysMixin is a class used by the database-dependent
|
The SpatialRefSysMixin is a class used by the database-dependent
|
||||||
|
@ -325,7 +327,7 @@ class SpatialRefSysMixin(object):
|
||||||
radius, flattening = sphere_params
|
radius, flattening = sphere_params
|
||||||
return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening)
|
return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
Returns the string representation. If GDAL is installed,
|
Returns the string representation. If GDAL is installed,
|
||||||
it will be 'pretty' OGC WKT.
|
it will be 'pretty' OGC WKT.
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
"""
|
"""
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GeometryColumns(models.Model):
|
class GeometryColumns(models.Model):
|
||||||
"Maps to the Oracle USER_SDO_GEOM_METADATA table."
|
"Maps to the Oracle USER_SDO_GEOM_METADATA table."
|
||||||
table_name = models.CharField(max_length=32)
|
table_name = models.CharField(max_length=32)
|
||||||
|
@ -36,7 +38,7 @@ class GeometryColumns(models.Model):
|
||||||
"""
|
"""
|
||||||
return 'column_name'
|
return 'column_name'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return '%s - %s (SRID: %s)' % (self.table_name, self.column_name, self.srid)
|
return '%s - %s (SRID: %s)' % (self.table_name, self.column_name, self.srid)
|
||||||
|
|
||||||
class SpatialRefSys(models.Model, SpatialRefSysMixin):
|
class SpatialRefSys(models.Model, SpatialRefSysMixin):
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
"""
|
"""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GeometryColumns(models.Model):
|
class GeometryColumns(models.Model):
|
||||||
"""
|
"""
|
||||||
The 'geometry_columns' table from the PostGIS. See the PostGIS
|
The 'geometry_columns' table from the PostGIS. See the PostGIS
|
||||||
|
@ -37,7 +39,7 @@ class GeometryColumns(models.Model):
|
||||||
"""
|
"""
|
||||||
return 'f_geometry_column'
|
return 'f_geometry_column'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s.%s - %dD %s field (SRID: %d)" % \
|
return "%s.%s - %dD %s field (SRID: %d)" % \
|
||||||
(self.f_table_name, self.f_geometry_column,
|
(self.f_table_name, self.f_geometry_column,
|
||||||
self.coord_dimension, self.type, self.srid)
|
self.coord_dimension, self.type, self.srid)
|
||||||
|
|
|
@ -30,6 +30,7 @@ class SpatiaLiteCreation(DatabaseCreation):
|
||||||
|
|
||||||
self.connection.close()
|
self.connection.close()
|
||||||
self.connection.settings_dict["NAME"] = test_database_name
|
self.connection.settings_dict["NAME"] = test_database_name
|
||||||
|
self.connection.ops.confirm_spatial_components_versions()
|
||||||
|
|
||||||
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
|
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
|
||||||
self.load_spatialite_sql()
|
self.load_spatialite_sql()
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
"""
|
"""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GeometryColumns(models.Model):
|
class GeometryColumns(models.Model):
|
||||||
"""
|
"""
|
||||||
The 'geometry_columns' table from SpatiaLite.
|
The 'geometry_columns' table from SpatiaLite.
|
||||||
|
@ -35,7 +37,7 @@ class GeometryColumns(models.Model):
|
||||||
"""
|
"""
|
||||||
return 'f_geometry_column'
|
return 'f_geometry_column'
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s.%s - %dD %s field (SRID: %d)" % \
|
return "%s.%s - %dD %s field (SRID: %d)" % \
|
||||||
(self.f_table_name, self.f_geometry_column,
|
(self.f_table_name, self.f_geometry_column,
|
||||||
self.coord_dimension, self.type, self.srid)
|
self.coord_dimension, self.type, self.srid)
|
||||||
|
|
|
@ -113,6 +113,12 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
super(DatabaseOperations, self).__init__(connection)
|
super(DatabaseOperations, self).__init__(connection)
|
||||||
|
|
||||||
|
# Creating the GIS terms dictionary.
|
||||||
|
gis_terms = ['isnull']
|
||||||
|
gis_terms += self.geometry_functions.keys()
|
||||||
|
self.gis_terms = dict([(term, None) for term in gis_terms])
|
||||||
|
|
||||||
|
def confirm_spatial_components_versions(self):
|
||||||
# Determine the version of the SpatiaLite library.
|
# Determine the version of the SpatiaLite library.
|
||||||
try:
|
try:
|
||||||
vtup = self.spatialite_version_tuple()
|
vtup = self.spatialite_version_tuple()
|
||||||
|
@ -129,11 +135,6 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
'SQL loaded on this database?' %
|
'SQL loaded on this database?' %
|
||||||
(self.connection.settings_dict['NAME'], msg))
|
(self.connection.settings_dict['NAME'], msg))
|
||||||
|
|
||||||
# Creating the GIS terms dictionary.
|
|
||||||
gis_terms = ['isnull']
|
|
||||||
gis_terms += list(self.geometry_functions)
|
|
||||||
self.gis_terms = dict([(term, None) for term in gis_terms])
|
|
||||||
|
|
||||||
if version >= (2, 4, 0):
|
if version >= (2, 4, 0):
|
||||||
# Spatialite 2.4.0-RC4 added AsGML and AsKML, however both
|
# Spatialite 2.4.0-RC4 added AsGML and AsKML, however both
|
||||||
# RC2 (shipped in popular Debian/Ubuntu packages) and RC4
|
# RC2 (shipped in popular Debian/Ubuntu packages) and RC4
|
||||||
|
|
|
@ -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."
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ test_suites = [test_driver.suite(),
|
||||||
def suite():
|
def suite():
|
||||||
"Builds a test suite for the GDAL tests."
|
"Builds a test suite for the GDAL tests."
|
||||||
s = TestSuite()
|
s = TestSuite()
|
||||||
map(s.addTest, test_suites)
|
for test_suite in test_suites:
|
||||||
|
s.addTest(test_suite)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def run(verbosity=1):
|
def run(verbosity=1):
|
||||||
|
|
|
@ -2,8 +2,10 @@ from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Poly
|
||||||
from django.utils.functional import total_ordering
|
from django.utils.functional import total_ordering
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GEvent(object):
|
class GEvent(object):
|
||||||
"""
|
"""
|
||||||
A Python wrapper for the Google GEvent object.
|
A Python wrapper for the Google GEvent object.
|
||||||
|
@ -48,10 +50,11 @@ class GEvent(object):
|
||||||
self.event = event
|
self.event = event
|
||||||
self.action = action
|
self.action = action
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
"Returns the parameter part of a GEvent."
|
"Returns the parameter part of a GEvent."
|
||||||
return mark_safe('"%s", %s' %(self.event, self.action))
|
return mark_safe('"%s", %s' %(self.event, self.action))
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GOverlayBase(object):
|
class GOverlayBase(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.events = []
|
self.events = []
|
||||||
|
@ -64,7 +67,7 @@ class GOverlayBase(object):
|
||||||
"Attaches a GEvent to the overlay object."
|
"Attaches a GEvent to the overlay object."
|
||||||
self.events.append(event)
|
self.events.append(event)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
"The string representation is the JavaScript API call."
|
"The string representation is the JavaScript API call."
|
||||||
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
|
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -1,50 +1,58 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SouthTexasCity(models.Model):
|
class SouthTexasCity(models.Model):
|
||||||
"City model on projected coordinate system for South Texas."
|
"City model on projected coordinate system for South Texas."
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField(srid=32140)
|
point = models.PointField(srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SouthTexasCityFt(models.Model):
|
class SouthTexasCityFt(models.Model):
|
||||||
"Same City model as above, but U.S. survey feet are the units."
|
"Same City model as above, but U.S. survey feet are the units."
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField(srid=2278)
|
point = models.PointField(srid=2278)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class AustraliaCity(models.Model):
|
class AustraliaCity(models.Model):
|
||||||
"City model for Australia, using WGS84."
|
"City model for Australia, using WGS84."
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField()
|
point = models.PointField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class CensusZipcode(models.Model):
|
class CensusZipcode(models.Model):
|
||||||
"Model for a few South Texas ZIP codes (in original Census NAD83)."
|
"Model for a few South Texas ZIP codes (in original Census NAD83)."
|
||||||
name = models.CharField(max_length=5)
|
name = models.CharField(max_length=5)
|
||||||
poly = models.PolygonField(srid=4269)
|
poly = models.PolygonField(srid=4269)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SouthTexasZipcode(models.Model):
|
class SouthTexasZipcode(models.Model):
|
||||||
"Model for a few South Texas ZIP codes."
|
"Model for a few South Texas ZIP codes."
|
||||||
name = models.CharField(max_length=5)
|
name = models.CharField(max_length=5)
|
||||||
poly = models.PolygonField(srid=32140, null=True)
|
poly = models.PolygonField(srid=32140, null=True)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Interstate(models.Model):
|
class Interstate(models.Model):
|
||||||
"Geodetic model for U.S. Interstates."
|
"Geodetic model for U.S. Interstates."
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
path = models.LineStringField()
|
path = models.LineStringField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class SouthTexasInterstate(models.Model):
|
class SouthTexasInterstate(models.Model):
|
||||||
"Projected model for South Texas Interstates."
|
"Projected model for South Texas Interstates."
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
path = models.LineStringField(srid=32140)
|
path = models.LineStringField(srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
|
@ -1,59 +1,67 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class City3D(models.Model):
|
class City3D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField(dim=3)
|
point = models.PointField(dim=3)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Interstate2D(models.Model):
|
class Interstate2D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
line = models.LineStringField(srid=4269)
|
line = models.LineStringField(srid=4269)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Interstate3D(models.Model):
|
class Interstate3D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
line = models.LineStringField(dim=3, srid=4269)
|
line = models.LineStringField(dim=3, srid=4269)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class InterstateProj2D(models.Model):
|
class InterstateProj2D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
line = models.LineStringField(srid=32140)
|
line = models.LineStringField(srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class InterstateProj3D(models.Model):
|
class InterstateProj3D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
line = models.LineStringField(dim=3, srid=32140)
|
line = models.LineStringField(dim=3, srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Polygon2D(models.Model):
|
class Polygon2D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
poly = models.PolygonField(srid=32140)
|
poly = models.PolygonField(srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Polygon3D(models.Model):
|
class Polygon3D(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
poly = models.PolygonField(dim=3, srid=32140)
|
poly = models.PolygonField(dim=3, srid=32140)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
class Point2D(models.Model):
|
class Point2D(models.Model):
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.gis import admin
|
from django.contrib.gis import admin
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class City(models.Model):
|
class City(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField()
|
point = models.PointField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
admin.site.register(City, admin.OSMGeoAdmin)
|
admin.site.register(City, admin.OSMGeoAdmin)
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.gis.tests.utils import mysql, spatialite
|
from django.contrib.gis.tests.utils import mysql, spatialite
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
# MySQL spatial indices can't handle NULL geometries.
|
# MySQL spatial indices can't handle NULL geometries.
|
||||||
null_flag = not mysql
|
null_flag = not mysql
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Country(models.Model):
|
class Country(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
mpoly = models.MultiPolygonField() # SRID, by default, is 4326
|
mpoly = models.MultiPolygonField() # SRID, by default, is 4326
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class City(models.Model):
|
class City(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField()
|
point = models.PointField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
# This is an inherited model from City
|
# This is an inherited model from City
|
||||||
class PennsylvaniaCity(City):
|
class PennsylvaniaCity(City):
|
||||||
|
@ -22,28 +25,31 @@ class PennsylvaniaCity(City):
|
||||||
founded = models.DateTimeField(null=True)
|
founded = models.DateTimeField(null=True)
|
||||||
objects = models.GeoManager() # TODO: This should be implicitly inherited.
|
objects = models.GeoManager() # TODO: This should be implicitly inherited.
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class State(models.Model):
|
class State(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
poly = models.PolygonField(null=null_flag) # Allowing NULL geometries here.
|
poly = models.PolygonField(null=null_flag) # Allowing NULL geometries here.
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Track(models.Model):
|
class Track(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
line = models.LineStringField()
|
line = models.LineStringField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
class Truth(models.Model):
|
class Truth(models.Model):
|
||||||
val = models.BooleanField()
|
val = models.BooleanField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
if not spatialite:
|
if not spatialite:
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Feature(models.Model):
|
class Feature(models.Model):
|
||||||
name = models.CharField(max_length=20)
|
name = models.CharField(max_length=20)
|
||||||
geom = models.GeometryField()
|
geom = models.GeometryField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
class MinusOneSRID(models.Model):
|
class MinusOneSRID(models.Model):
|
||||||
geom = models.PointField(srid=-1) # Minus one SRID.
|
geom = models.PointField(srid=-1) # Minus one SRID.
|
||||||
|
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class City(models.Model):
|
class City(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
point = models.PointField(geography=True)
|
point = models.PointField(geography=True)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Zipcode(models.Model):
|
class Zipcode(models.Model):
|
||||||
code = models.CharField(max_length=10)
|
code = models.CharField(max_length=10)
|
||||||
poly = models.PolygonField(geography=True)
|
poly = models.PolygonField(geography=True)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.code
|
def __str__(self): return self.code
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class County(models.Model):
|
class County(models.Model):
|
||||||
name = models.CharField(max_length=25)
|
name = models.CharField(max_length=25)
|
||||||
state = models.CharField(max_length=20)
|
state = models.CharField(max_length=20)
|
||||||
mpoly = models.MultiPolygonField(geography=True)
|
mpoly = models.MultiPolygonField(geography=True)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return ' County, '.join([self.name, self.state])
|
def __str__(self): return ' County, '.join([self.name, self.state])
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.localflavor.us.models import USStateField
|
from django.contrib.localflavor.us.models import USStateField
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Location(models.Model):
|
class Location(models.Model):
|
||||||
point = models.PointField()
|
point = models.PointField()
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.point.wkt
|
def __str__(self): return self.point.wkt
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class City(models.Model):
|
class City(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
state = USStateField()
|
state = USStateField()
|
||||||
location = models.ForeignKey(Location)
|
location = models.ForeignKey(Location)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
class AugmentedLocation(Location):
|
class AugmentedLocation(Location):
|
||||||
extra_text = models.TextField(blank=True)
|
extra_text = models.TextField(blank=True)
|
||||||
|
@ -22,6 +25,7 @@ class DirectoryEntry(models.Model):
|
||||||
location = models.ForeignKey(AugmentedLocation)
|
location = models.ForeignKey(AugmentedLocation)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Parcel(models.Model):
|
class Parcel(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
city = models.ForeignKey(City)
|
city = models.ForeignKey(City)
|
||||||
|
@ -31,7 +35,7 @@ class Parcel(models.Model):
|
||||||
border1 = models.PolygonField()
|
border1 = models.PolygonField()
|
||||||
border2 = models.PolygonField(srid=2276)
|
border2 = models.PolygonField(srid=2276)
|
||||||
objects = models.GeoManager()
|
objects = models.GeoManager()
|
||||||
def __unicode__(self): return self.name
|
def __str__(self): return self.name
|
||||||
|
|
||||||
# These use the GeoManager but do not have any geographic fields.
|
# These use the GeoManager but do not have any geographic fields.
|
||||||
class Author(models.Model):
|
class Author(models.Model):
|
||||||
|
|
|
@ -223,4 +223,4 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
|
||||||
|
|
||||||
if name_field:
|
if name_field:
|
||||||
yield ''
|
yield ''
|
||||||
yield ' def __unicode__(self): return self.%s' % name_field
|
yield ' def __str__(self): return self.%s' % name_field
|
||||||
|
|
|
@ -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"]))
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.encoding import force_text, StrAndUnicode
|
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||||
from django.contrib.messages import constants, utils
|
from django.contrib.messages import constants, utils
|
||||||
|
|
||||||
|
|
||||||
LEVEL_TAGS = utils.get_level_tags()
|
LEVEL_TAGS = utils.get_level_tags()
|
||||||
|
|
||||||
|
|
||||||
class Message(StrAndUnicode):
|
@python_2_unicode_compatible
|
||||||
|
class Message(object):
|
||||||
"""
|
"""
|
||||||
Represents an actual message that can be stored in any of the supported
|
Represents an actual message that can be stored in any of the supported
|
||||||
storage classes (typically session- or cookie-based) and rendered in a view
|
storage classes (typically session- or cookie-based) and rendered in a view
|
||||||
|
@ -35,7 +36,7 @@ class Message(StrAndUnicode):
|
||||||
return isinstance(other, Message) and self.level == other.level and \
|
return isinstance(other, Message) and self.level == other.level and \
|
||||||
self.message == other.message
|
self.message == other.message
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return force_text(self.message)
|
return force_text(self.message)
|
||||||
|
|
||||||
def _get_tags(self):
|
def _get_tags(self):
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Redirect(models.Model):
|
class Redirect(models.Model):
|
||||||
site = models.ForeignKey(Site)
|
site = models.ForeignKey(Site)
|
||||||
old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
|
old_path = models.CharField(_('redirect from'), max_length=200, db_index=True,
|
||||||
|
@ -16,5 +18,5 @@ class Redirect(models.Model):
|
||||||
unique_together=(('site', 'old_path'),)
|
unique_together=(('site', 'old_path'),)
|
||||||
ordering = ('old_path',)
|
ordering = ('old_path',)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return "%s ---> %s" % (self.old_path, self.new_path)
|
return "%s ---> %s" % (self.old_path, self.new_path)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
@ -12,6 +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 force_bytes
|
||||||
|
|
||||||
class CreateError(Exception):
|
class CreateError(Exception):
|
||||||
"""
|
"""
|
||||||
|
@ -78,15 +81,15 @@ class SessionBase(object):
|
||||||
"Returns the given session dictionary pickled and encoded as a string."
|
"Returns the given session dictionary pickled and encoded as a string."
|
||||||
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
|
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
|
||||||
hash = self._hash(pickled)
|
hash = self._hash(pickled)
|
||||||
return base64.encodestring(hash + ":" + pickled)
|
return base64.b64encode(hash.encode() + b":" + pickled).decode('ascii')
|
||||||
|
|
||||||
def decode(self, session_data):
|
def decode(self, session_data):
|
||||||
encoded_data = base64.decodestring(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(':', 1)
|
hash, pickled = encoded_data.split(b':', 1)
|
||||||
expected_hash = self._hash(pickled)
|
expected_hash = self._hash(pickled)
|
||||||
if not constant_time_compare(hash, expected_hash):
|
if not constant_time_compare(hash.decode(), expected_hash):
|
||||||
raise SuspiciousOperation("Session data corrupted")
|
raise SuspiciousOperation("Session data corrupted")
|
||||||
else:
|
else:
|
||||||
return pickle.loads(pickled)
|
return pickle.loads(pickled)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.contrib.sessions.backends.base import SessionBase, CreateError
|
from django.contrib.sessions.backends.base import SessionBase, CreateError
|
||||||
from django.core.exceptions import SuspiciousOperation
|
from django.core.exceptions import SuspiciousOperation
|
||||||
from django.db import IntegrityError, transaction, router
|
from django.db import IntegrityError, transaction, router
|
||||||
from django.utils.encoding import force_text
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ class SessionStore(SessionBase):
|
||||||
session_key = self.session_key,
|
session_key = self.session_key,
|
||||||
expire_date__gt=timezone.now()
|
expire_date__gt=timezone.now()
|
||||||
)
|
)
|
||||||
return self.decode(force_text(s.session_data))
|
return self.decode(s.session_data)
|
||||||
except (Session.DoesNotExist, SuspiciousOperation):
|
except (Session.DoesNotExist, SuspiciousOperation):
|
||||||
self.create()
|
self.create()
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -115,7 +115,7 @@ class SessionStore(SessionBase):
|
||||||
renamed = False
|
renamed = False
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
os.write(output_file_fd, self.encode(session_data))
|
os.write(output_file_fd, self.encode(session_data).encode())
|
||||||
finally:
|
finally:
|
||||||
os.close(output_file_fd)
|
os.close(output_file_fd)
|
||||||
os.rename(output_file_name, session_file_name)
|
os.rename(output_file_name, session_file_name)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
|
@ -12,8 +14,9 @@ class GenericViewsSitemapTests(SitemapTestsBase):
|
||||||
expected = ''
|
expected = ''
|
||||||
for username in User.objects.values_list("username", flat=True):
|
for username in User.objects.values_list("username", flat=True):
|
||||||
expected += "<url><loc>%s/users/%s/</loc></url>" % (self.base_url, username)
|
expected += "<url><loc>%s/users/%s/</loc></url>" % (self.base_url, username)
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
%s
|
%s
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % expected)
|
""" % expected
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
|
@ -21,11 +21,12 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||||
def test_simple_sitemap_index(self):
|
def test_simple_sitemap_index(self):
|
||||||
"A simple sitemap index can be rendered"
|
"A simple sitemap index can be rendered"
|
||||||
response = self.client.get('/simple/index.xml')
|
response = self.client.get('/simple/index.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
""" % self.base_url)
|
""" % self.base_url
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
|
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
|
||||||
|
@ -33,30 +34,34 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||||
def test_simple_sitemap_custom_index(self):
|
def test_simple_sitemap_custom_index(self):
|
||||||
"A simple sitemap index can be rendered with a custom template"
|
"A simple sitemap index can be rendered with a custom template"
|
||||||
response = self.client.get('/simple/custom-index.xml')
|
response = self.client.get('/simple/custom-index.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- This is a customised template -->
|
<!-- This is a customised template -->
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
""" % self.base_url)
|
""" % self.base_url
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
def test_simple_sitemap_section(self):
|
def test_simple_sitemap_section(self):
|
||||||
"A simple sitemap section can be rendered"
|
"A simple sitemap section can be rendered"
|
||||||
response = self.client.get('/simple/sitemap-simple.xml')
|
response = self.client.get('/simple/sitemap-simple.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % (self.base_url, date.today()))
|
""" % (self.base_url, date.today())
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
def test_simple_sitemap(self):
|
def test_simple_sitemap(self):
|
||||||
"A simple sitemap can be rendered"
|
"A simple sitemap can be rendered"
|
||||||
response = self.client.get('/simple/sitemap.xml')
|
response = self.client.get('/simple/sitemap.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % (self.base_url, date.today()))
|
""" % (self.base_url, date.today())
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
|
TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__), 'templates'),)
|
||||||
|
@ -64,12 +69,13 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||||
def test_simple_custom_sitemap(self):
|
def test_simple_custom_sitemap(self):
|
||||||
"A simple sitemap can be rendered with a custom template"
|
"A simple sitemap can be rendered with a custom template"
|
||||||
response = self.client.get('/simple/custom-sitemap.xml')
|
response = self.client.get('/simple/custom-sitemap.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- This is a customised template -->
|
<!-- This is a customised template -->
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % (self.base_url, date.today()))
|
""" % (self.base_url, date.today())
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
@skipUnless(settings.USE_I18N, "Internationalization is not enabled")
|
@skipUnless(settings.USE_I18N, "Internationalization is not enabled")
|
||||||
@override_settings(USE_L10N=True)
|
@override_settings(USE_L10N=True)
|
||||||
|
@ -90,11 +96,12 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||||
# installed doesn't raise an exception
|
# installed doesn't raise an exception
|
||||||
Site._meta.installed = False
|
Site._meta.installed = False
|
||||||
response = self.client.get('/simple/sitemap.xml')
|
response = self.client.get('/simple/sitemap.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>http://testserver/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>http://testserver/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % date.today())
|
""" % date.today()
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
@skipUnless("django.contrib.sites" in settings.INSTALLED_APPS,
|
@skipUnless("django.contrib.sites" in settings.INSTALLED_APPS,
|
||||||
"django.contrib.sites app not installed.")
|
"django.contrib.sites app not installed.")
|
||||||
|
@ -131,8 +138,9 @@ class HTTPSitemapTests(SitemapTestsBase):
|
||||||
Check that a cached sitemap index can be rendered (#2713).
|
Check that a cached sitemap index can be rendered (#2713).
|
||||||
"""
|
"""
|
||||||
response = self.client.get('/cached/index.xml')
|
response = self.client.get('/cached/index.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap><loc>%s/cached/sitemap-simple.xml</loc></sitemap>
|
<sitemap><loc>%s/cached/sitemap-simple.xml</loc></sitemap>
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
""" % self.base_url)
|
""" % self.base_url
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
@ -11,20 +13,22 @@ class HTTPSSitemapTests(SitemapTestsBase):
|
||||||
def test_secure_sitemap_index(self):
|
def test_secure_sitemap_index(self):
|
||||||
"A secure sitemap index can be rendered"
|
"A secure sitemap index can be rendered"
|
||||||
response = self.client.get('/secure/index.xml')
|
response = self.client.get('/secure/index.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap><loc>%s/secure/sitemap-simple.xml</loc></sitemap>
|
<sitemap><loc>%s/secure/sitemap-simple.xml</loc></sitemap>
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
""" % self.base_url)
|
""" % self.base_url
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
def test_secure_sitemap_section(self):
|
def test_secure_sitemap_section(self):
|
||||||
"A secure sitemap section can be rendered"
|
"A secure sitemap section can be rendered"
|
||||||
response = self.client.get('/secure/sitemap-simple.xml')
|
response = self.client.get('/secure/sitemap-simple.xml')
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % (self.base_url, date.today()))
|
""" % (self.base_url, date.today())
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
@override_settings(SECURE_PROXY_SSL_HEADER=False)
|
@override_settings(SECURE_PROXY_SSL_HEADER=False)
|
||||||
|
@ -34,17 +38,19 @@ class HTTPSDetectionSitemapTests(SitemapTestsBase):
|
||||||
def test_sitemap_index_with_https_request(self):
|
def test_sitemap_index_with_https_request(self):
|
||||||
"A sitemap index requested in HTTPS is rendered with HTTPS links"
|
"A sitemap index requested in HTTPS is rendered with HTTPS links"
|
||||||
response = self.client.get('/simple/index.xml', **self.extra)
|
response = self.client.get('/simple/index.xml', **self.extra)
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
<sitemap><loc>%s/simple/sitemap-simple.xml</loc></sitemap>
|
||||||
</sitemapindex>
|
</sitemapindex>
|
||||||
""" % self.base_url.replace('http://', 'https://'))
|
""" % self.base_url.replace('http://', 'https://')
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
||||||
def test_sitemap_section_with_https_request(self):
|
def test_sitemap_section_with_https_request(self):
|
||||||
"A sitemap section requested in HTTPS is rendered with HTTPS links"
|
"A sitemap section requested in HTTPS is rendered with HTTPS links"
|
||||||
response = self.client.get('/simple/sitemap-simple.xml', **self.extra)
|
response = self.client.get('/simple/sitemap-simple.xml', **self.extra)
|
||||||
self.assertEqual(response.content, """<?xml version="1.0" encoding="UTF-8"?>
|
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
<url><loc>%s/location/</loc><lastmod>%s</lastmod><changefreq>never</changefreq><priority>0.5</priority></url>
|
||||||
</urlset>
|
</urlset>
|
||||||
""" % (self.base_url.replace('http://', 'https://'), date.today()))
|
""" % (self.base_url.replace('http://', 'https://'), date.today())
|
||||||
|
self.assertEqual(response.content, expected_content.encode('utf-8'))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
SITE_CACHE = {}
|
SITE_CACHE = {}
|
||||||
|
@ -32,6 +33,7 @@ class SiteManager(models.Manager):
|
||||||
SITE_CACHE = {}
|
SITE_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Site(models.Model):
|
class Site(models.Model):
|
||||||
|
|
||||||
domain = models.CharField(_('domain name'), max_length=100)
|
domain = models.CharField(_('domain name'), max_length=100)
|
||||||
|
@ -44,7 +46,7 @@ class Site(models.Model):
|
||||||
verbose_name_plural = _('sites')
|
verbose_name_plural = _('sites')
|
||||||
ordering = ('domain',)
|
ordering = ('domain',)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.domain
|
return self.domain
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
@ -62,6 +64,7 @@ class Site(models.Model):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class RequestSite(object):
|
class RequestSite(object):
|
||||||
"""
|
"""
|
||||||
A class that shares the primary interface of Site (i.e., it has
|
A class that shares the primary interface of Site (i.e., it has
|
||||||
|
@ -73,7 +76,7 @@ class RequestSite(object):
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
self.domain = self.name = request.get_host()
|
self.domain = self.name = request.get_host()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.domain
|
return self.domain
|
||||||
|
|
||||||
def save(self, force_insert=False, force_update=False):
|
def save(self, force_insert=False, force_update=False):
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ class CachedFilesMixin(object):
|
||||||
default_template = """url("%s")"""
|
default_template = """url("%s")"""
|
||||||
patterns = (
|
patterns = (
|
||||||
("*.css", (
|
("*.css", (
|
||||||
br"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""",
|
r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""",
|
||||||
(br"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""),
|
(r"""(@import\s*["']\s*(.*?)["'])""", """@import url("%s")"""),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ class CachedFilesMixin(object):
|
||||||
def hashed_name(self, name, content=None):
|
def hashed_name(self, name, content=None):
|
||||||
parsed_name = urlsplit(unquote(name))
|
parsed_name = urlsplit(unquote(name))
|
||||||
clean_name = parsed_name.path.strip()
|
clean_name = parsed_name.path.strip()
|
||||||
|
opened = False
|
||||||
if content is None:
|
if content is None:
|
||||||
if not self.exists(clean_name):
|
if not self.exists(clean_name):
|
||||||
raise ValueError("The file '%s' could not be found with %r." %
|
raise ValueError("The file '%s' could not be found with %r." %
|
||||||
|
@ -96,9 +97,14 @@ class CachedFilesMixin(object):
|
||||||
except IOError:
|
except IOError:
|
||||||
# Handle directory paths and fragments
|
# Handle directory paths and fragments
|
||||||
return name
|
return name
|
||||||
|
opened = True
|
||||||
|
try:
|
||||||
|
file_hash = self.file_hash(clean_name, content)
|
||||||
|
finally:
|
||||||
|
if opened:
|
||||||
|
content.close()
|
||||||
path, filename = os.path.split(clean_name)
|
path, filename = os.path.split(clean_name)
|
||||||
root, ext = os.path.splitext(filename)
|
root, ext = os.path.splitext(filename)
|
||||||
file_hash = self.file_hash(clean_name, content)
|
|
||||||
if file_hash is not None:
|
if file_hash is not None:
|
||||||
file_hash = ".%s" % file_hash
|
file_hash = ".%s" % file_hash
|
||||||
hashed_name = os.path.join(path, "%s%s%s" %
|
hashed_name = os.path.join(path, "%s%s%s" %
|
||||||
|
@ -112,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):
|
||||||
"""
|
"""
|
||||||
|
@ -248,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
|
||||||
|
@ -261,7 +267,7 @@ class CachedFilesMixin(object):
|
||||||
hashed_name = force_text(saved_name.replace('\\', '/'))
|
hashed_name = force_text(saved_name.replace('\\', '/'))
|
||||||
|
|
||||||
# and then set the cache accordingly
|
# and then set the cache accordingly
|
||||||
hashed_paths[self.cache_key(name)] = hashed_name
|
hashed_paths[self.cache_key(name.replace('\\', '/'))] = hashed_name
|
||||||
yield name, hashed_name, processed
|
yield name, hashed_name, processed
|
||||||
|
|
||||||
# Finally set the cache
|
# Finally set the cache
|
||||||
|
|
|
@ -106,7 +106,7 @@ class Feed(object):
|
||||||
subtitle = self.__get_dynamic_attr('subtitle', obj),
|
subtitle = self.__get_dynamic_attr('subtitle', obj),
|
||||||
link = link,
|
link = link,
|
||||||
description = self.__get_dynamic_attr('description', obj),
|
description = self.__get_dynamic_attr('description', obj),
|
||||||
language = settings.LANGUAGE_CODE.decode(),
|
language = settings.LANGUAGE_CODE,
|
||||||
feed_url = add_domain(
|
feed_url = add_domain(
|
||||||
current_site.domain,
|
current_site.domain,
|
||||||
self.__get_dynamic_attr('feed_url', obj) or request.path,
|
self.__get_dynamic_attr('feed_url', obj) or request.path,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"Base Cache class."
|
"Base Cache class."
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
|
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
|
||||||
from django.utils.encoding import smart_bytes
|
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
class InvalidCacheBackendError(ImproperlyConfigured):
|
class InvalidCacheBackendError(ImproperlyConfigured):
|
||||||
|
@ -23,7 +23,7 @@ def default_key_func(key, key_prefix, version):
|
||||||
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
|
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
|
||||||
function with custom key making behavior.
|
function with custom key making behavior.
|
||||||
"""
|
"""
|
||||||
return ':'.join([key_prefix, str(version), smart_bytes(key)])
|
return ':'.join([key_prefix, str(version), key])
|
||||||
|
|
||||||
def get_key_func(key_func):
|
def get_key_func(key_func):
|
||||||
"""
|
"""
|
||||||
|
@ -62,7 +62,7 @@ class BaseCache(object):
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
self._cull_frequency = 3
|
self._cull_frequency = 3
|
||||||
|
|
||||||
self.key_prefix = smart_bytes(params.get('KEY_PREFIX', ''))
|
self.key_prefix = params.get('KEY_PREFIX', '')
|
||||||
self.version = params.get('VERSION', 1)
|
self.version = params.get('VERSION', 1)
|
||||||
self.key_func = get_key_func(params.get('KEY_FUNCTION', None))
|
self.key_func = get_key_func(params.get('KEY_FUNCTION', None))
|
||||||
|
|
||||||
|
|
|
@ -12,6 +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 force_bytes
|
||||||
|
|
||||||
|
|
||||||
class Options(object):
|
class Options(object):
|
||||||
|
@ -72,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.decodestring(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)
|
||||||
|
@ -103,7 +104,7 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
if num > self._max_entries:
|
if num > self._max_entries:
|
||||||
self._cull(db, cursor, now)
|
self._cull(db, cursor, now)
|
||||||
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||||
encoded = base64.encodestring(pickled).strip()
|
encoded = base64.b64encode(pickled).strip()
|
||||||
cursor.execute("SELECT cache_key, expires FROM %s "
|
cursor.execute("SELECT cache_key, expires FROM %s "
|
||||||
"WHERE cache_key = %%s" % table, [key])
|
"WHERE cache_key = %%s" % table, [key])
|
||||||
try:
|
try:
|
||||||
|
@ -166,7 +167,7 @@ class DatabaseCache(BaseDatabaseCache):
|
||||||
cursor.execute("SELECT COUNT(*) FROM %s" % table)
|
cursor.execute("SELECT COUNT(*) FROM %s" % table)
|
||||||
num = cursor.fetchone()[0]
|
num = cursor.fetchone()[0]
|
||||||
if num > self._max_entries:
|
if num > self._max_entries:
|
||||||
cull_num = num / self._cull_frequency
|
cull_num = num // self._cull_frequency
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
connections[db].ops.cache_key_culling_sql() % table,
|
connections[db].ops.cache_key_culling_sql() % table,
|
||||||
[cull_num])
|
[cull_num])
|
||||||
|
|
|
@ -10,6 +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 force_bytes
|
||||||
|
|
||||||
class FileBasedCache(BaseCache):
|
class FileBasedCache(BaseCache):
|
||||||
def __init__(self, dir, params):
|
def __init__(self, dir, params):
|
||||||
|
@ -136,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(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,6 +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 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):
|
||||||
|
@ -50,6 +51,10 @@ class BaseMemcachedCache(BaseCache):
|
||||||
timeout += int(time.time())
|
timeout += int(time.time())
|
||||||
return int(timeout)
|
return int(timeout)
|
||||||
|
|
||||||
|
def make_key(self, key, version=None):
|
||||||
|
# Python 2 memcache requires the key to be a byte string.
|
||||||
|
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)
|
||||||
return self._cache.add(key, value, self._get_memcache_timeout(timeout))
|
return self._cache.add(key, value, self._get_memcache_timeout(timeout))
|
||||||
|
|
|
@ -6,12 +6,15 @@ and returns a dictionary to add to the context.
|
||||||
These are referenced from the setting TEMPLATE_CONTEXT_PROCESSORS and used by
|
These are referenced from the setting TEMPLATE_CONTEXT_PROCESSORS and used by
|
||||||
RequestContext.
|
RequestContext.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.middleware.csrf import get_token
|
from django.middleware.csrf import get_token
|
||||||
from django.utils.encoding import smart_bytes
|
from django.utils import six
|
||||||
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
|
||||||
|
|
||||||
def csrf(request):
|
def csrf(request):
|
||||||
"""
|
"""
|
||||||
Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
|
Context processor that provides a CSRF token, or the string 'NOTPROVIDED' if
|
||||||
|
@ -23,10 +26,10 @@ def csrf(request):
|
||||||
# In order to be able to provide debugging info in the
|
# In order to be able to provide debugging info in the
|
||||||
# case of misconfiguration, we use a sentinel value
|
# case of misconfiguration, we use a sentinel value
|
||||||
# instead of returning an empty dict.
|
# instead of returning an empty dict.
|
||||||
return b'NOTPROVIDED'
|
return 'NOTPROVIDED'
|
||||||
else:
|
else:
|
||||||
return smart_bytes(token)
|
return smart_text(token)
|
||||||
_get_val = lazy(_get_val, str)
|
_get_val = lazy(_get_val, six.text_type)
|
||||||
|
|
||||||
return {'csrf_token': _get_val() }
|
return {'csrf_token': _get_val() }
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from io import BytesIO
|
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
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class File(FileProxyMixin):
|
class File(FileProxyMixin):
|
||||||
DEFAULT_CHUNK_SIZE = 64 * 2**10
|
DEFAULT_CHUNK_SIZE = 64 * 2**10
|
||||||
|
|
||||||
|
@ -18,9 +21,6 @@ class File(FileProxyMixin):
|
||||||
self.mode = file.mode
|
self.mode = file.mode
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return smart_bytes(self.name or '')
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return smart_text(self.name or '')
|
return smart_text(self.name or '')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -65,8 +65,10 @@ class File(FileProxyMixin):
|
||||||
if not chunk_size:
|
if not chunk_size:
|
||||||
chunk_size = self.DEFAULT_CHUNK_SIZE
|
chunk_size = self.DEFAULT_CHUNK_SIZE
|
||||||
|
|
||||||
if hasattr(self, 'seek'):
|
try:
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
except (AttributeError, UnsupportedOperation):
|
||||||
|
pass
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data = self.read(chunk_size)
|
data = self.read(chunk_size)
|
||||||
|
@ -124,13 +126,15 @@ class File(FileProxyMixin):
|
||||||
def close(self):
|
def close(self):
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class ContentFile(File):
|
class ContentFile(File):
|
||||||
"""
|
"""
|
||||||
A File-like object that takes just raw content, rather than an actual file.
|
A File-like object that takes just raw content, rather than an actual 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):
|
||||||
|
|
|
@ -66,7 +66,7 @@ def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_ove
|
||||||
try:
|
try:
|
||||||
locks.lock(fd, locks.LOCK_EX)
|
locks.lock(fd, locks.LOCK_EX)
|
||||||
current_chunk = None
|
current_chunk = None
|
||||||
while current_chunk != '':
|
while current_chunk != b'':
|
||||||
current_chunk = old_file.read(chunk_size)
|
current_chunk = old_file.read(chunk_size)
|
||||||
os.write(fd, current_chunk)
|
os.write(fd, current_chunk)
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -195,10 +195,17 @@ 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)
|
||||||
|
if _file is not None:
|
||||||
|
_file.close()
|
||||||
|
else:
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.EEXIST:
|
if e.errno == errno.EEXIST:
|
||||||
|
|
|
@ -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_bytes
|
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_bytes("<%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):
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile
|
from django.core.files.uploadedfile import TemporaryUploadedFile, InMemoryUploadedFile
|
||||||
from django.utils import importlib
|
from django.utils import importlib
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
__all__ = ['UploadFileException','StopUpload', 'SkipFile', 'FileUploadHandler',
|
__all__ = ['UploadFileException','StopUpload', 'SkipFile', 'FileUploadHandler',
|
||||||
'TemporaryFileUploadHandler', 'MemoryFileUploadHandler',
|
'TemporaryFileUploadHandler', 'MemoryFileUploadHandler',
|
||||||
|
@ -21,6 +22,7 @@ class UploadFileException(Exception):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class StopUpload(UploadFileException):
|
class StopUpload(UploadFileException):
|
||||||
"""
|
"""
|
||||||
This exception is raised when an upload must abort.
|
This exception is raised when an upload must abort.
|
||||||
|
@ -33,7 +35,7 @@ class StopUpload(UploadFileException):
|
||||||
"""
|
"""
|
||||||
self.connection_reset = connection_reset
|
self.connection_reset = connection_reset
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
if self.connection_reset:
|
if self.connection_reset:
|
||||||
return 'StopUpload: Halt current upload.'
|
return 'StopUpload: Halt current upload.'
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
|
@ -125,10 +126,10 @@ class BaseHandler(object):
|
||||||
|
|
||||||
# Complain if the view returned None (a common error).
|
# Complain if the view returned None (a common error).
|
||||||
if response is None:
|
if response is None:
|
||||||
try:
|
if isinstance(callback, types.FunctionType): # FBV
|
||||||
view_name = callback.func_name # If it's a function
|
view_name = callback.__name__
|
||||||
except AttributeError:
|
else: # CBV
|
||||||
view_name = callback.__class__.__name__ + '.__call__' # If it's a class
|
view_name = callback.__class__.__name__ + '.__call__'
|
||||||
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
|
raise ValueError("The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name))
|
||||||
|
|
||||||
# If the response supports deferred rendering, apply template
|
# If the response supports deferred rendering, apply template
|
||||||
|
@ -152,10 +153,8 @@ class BaseHandler(object):
|
||||||
callback, param_dict = resolver.resolve404()
|
callback, param_dict = resolver.resolve404()
|
||||||
response = callback(request, **param_dict)
|
response = callback(request, **param_dict)
|
||||||
except:
|
except:
|
||||||
try:
|
|
||||||
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
|
|
||||||
finally:
|
|
||||||
signals.got_request_exception.send(sender=self.__class__, request=request)
|
signals.got_request_exception.send(sender=self.__class__, request=request)
|
||||||
|
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
|
||||||
except exceptions.PermissionDenied:
|
except exceptions.PermissionDenied:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
'Forbidden (Permission denied): %s', request.path,
|
'Forbidden (Permission denied): %s', request.path,
|
||||||
|
@ -167,12 +166,10 @@ class BaseHandler(object):
|
||||||
callback, param_dict = resolver.resolve403()
|
callback, param_dict = resolver.resolve403()
|
||||||
response = callback(request, **param_dict)
|
response = callback(request, **param_dict)
|
||||||
except:
|
except:
|
||||||
try:
|
|
||||||
response = self.handle_uncaught_exception(request,
|
|
||||||
resolver, sys.exc_info())
|
|
||||||
finally:
|
|
||||||
signals.got_request_exception.send(
|
signals.got_request_exception.send(
|
||||||
sender=self.__class__, request=request)
|
sender=self.__class__, request=request)
|
||||||
|
response = self.handle_uncaught_exception(request,
|
||||||
|
resolver, sys.exc_info())
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
|
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
|
||||||
raise
|
raise
|
||||||
|
@ -225,7 +222,7 @@ class BaseHandler(object):
|
||||||
|
|
||||||
# If Http500 handler is not installed, re-raise last exception
|
# If Http500 handler is not installed, re-raise last exception
|
||||||
if resolver.urlconf_module is None:
|
if resolver.urlconf_module is None:
|
||||||
six.reraise(exc_info[1], None, exc_info[2])
|
six.reraise(*exc_info)
|
||||||
# Return an HttpResponse that displays a friendly error message.
|
# Return an HttpResponse that displays a friendly error message.
|
||||||
callback, param_dict = resolver.resolve500()
|
callback, param_dict = resolver.resolve500()
|
||||||
return callback(request, **param_dict)
|
return callback(request, **param_dict)
|
||||||
|
|
|
@ -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_bytes, 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_bytes(status), response_headers)
|
start_response(force_str(status), response_headers)
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -99,7 +99,12 @@ def sanitize_address(addr, encoding):
|
||||||
if isinstance(addr, six.string_types):
|
if isinstance(addr, six.string_types):
|
||||||
addr = parseaddr(force_text(addr))
|
addr = parseaddr(force_text(addr))
|
||||||
nm, addr = addr
|
nm, addr = addr
|
||||||
|
# This try-except clause is needed on Python 3 < 3.2.4
|
||||||
|
# http://bugs.python.org/issue14291
|
||||||
|
try:
|
||||||
nm = Header(nm, encoding).encode()
|
nm = Header(nm, encoding).encode()
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
nm = Header(nm, 'utf-8').encode()
|
||||||
try:
|
try:
|
||||||
addr.encode('ascii')
|
addr.encode('ascii')
|
||||||
except UnicodeEncodeError: # IDN
|
except UnicodeEncodeError: # IDN
|
||||||
|
|
|
@ -55,10 +55,15 @@ def find_management_module(app_name):
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
if os.path.basename(os.getcwd()) != part:
|
if os.path.basename(os.getcwd()) != part:
|
||||||
raise e
|
raise e
|
||||||
|
else:
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
|
|
||||||
while parts:
|
while parts:
|
||||||
part = parts.pop()
|
part = parts.pop()
|
||||||
f, path, descr = imp.find_module(part, path and [path] or None)
|
f, path, descr = imp.find_module(part, path and [path] or None)
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def load_command_class(app_name, name):
|
def load_command_class(app_name, name):
|
||||||
|
|
|
@ -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]
|
||||||
|
try:
|
||||||
connection.check_constraints(table_names=table_names)
|
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,32 +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 = map(lambda p: p.endswith(dir_suffix)
|
norm_patterns = [p[:-len(dir_suffix)] if p.endswith(dir_suffix) else p for p in ignore_patterns]
|
||||||
and p[:-len(dir_suffix)] or p, ignore_patterns)
|
all_files = []
|
||||||
for dirpath, dirnames, filenames in os.walk(root, topdown, onerror):
|
for dirpath, dirnames, filenames in os.walk(root, topdown=True, followlinks=symlinks):
|
||||||
remove_dirs = []
|
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)
|
|
||||||
for dirname in remove_dirs:
|
|
||||||
dirnames.remove(dirname)
|
dirnames.remove(dirname)
|
||||||
if verbosity > 1:
|
if verbosity > 1:
|
||||||
stdout.write('ignoring directory %s\n' % dirname)
|
stdout.write('ignoring directory %s\n' % dirname)
|
||||||
yield (dirpath, dirnames, filenames)
|
for filename in filenames:
|
||||||
if followlinks:
|
if is_ignored(os.path.normpath(os.path.join(dirpath, filename)), ignore_patterns):
|
||||||
for d in dirnames:
|
if verbosity > 1:
|
||||||
p = os.path.join(dirpath, d)
|
stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
|
||||||
if os.path.islink(p):
|
else:
|
||||||
for link_dirpath, link_dirnames, link_filenames in walk(p):
|
all_files.extend([(dirpath, filename)])
|
||||||
yield (link_dirpath, link_dirnames, link_filenames)
|
all_files.sort()
|
||||||
|
return all_files
|
||||||
|
|
||||||
def is_ignored(path, ignore_patterns):
|
def is_ignored(path, ignore_patterns):
|
||||||
"""
|
"""
|
||||||
|
@ -83,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
|
||||||
|
@ -144,7 +122,7 @@ def write_pot_file(potfile, msgs, file, work_file, is_templatized):
|
||||||
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
msgs = '\n'.join(dropwhile(len, msgs.split('\n')))
|
||||||
else:
|
else:
|
||||||
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8')
|
||||||
with open(potfile, 'ab') as fp:
|
with open(potfile, 'a') as fp:
|
||||||
fp.write(msgs)
|
fp.write(msgs)
|
||||||
|
|
||||||
def process_file(file, dirpath, potfile, domain, verbosity,
|
def process_file(file, dirpath, potfile, domain, verbosity,
|
||||||
|
@ -252,7 +230,7 @@ def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
|
||||||
msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
|
msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
|
||||||
msgs = msgs.replace(
|
msgs = msgs.replace(
|
||||||
"#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "")
|
"#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "")
|
||||||
with open(pofile, 'wb') as fp:
|
with open(pofile, 'w') as fp:
|
||||||
fp.write(msgs)
|
fp.write(msgs)
|
||||||
os.unlink(potfile)
|
os.unlink(potfile)
|
||||||
if no_obsolete:
|
if no_obsolete:
|
||||||
|
|
|
@ -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"),
|
||||||
|
os.path.expanduser('~/.pythonrc.py')):
|
||||||
if pythonrc and os.path.isfile(pythonrc):
|
if pythonrc and os.path.isfile(pythonrc):
|
||||||
try:
|
try:
|
||||||
execfile(pythonrc)
|
with open(pythonrc) as handle:
|
||||||
|
exec(compile(handle.read(), pythonrc, 'exec'))
|
||||||
except NameError:
|
except NameError:
|
||||||
pass
|
pass
|
||||||
# This will import .pythonrc.py as a side-effect
|
|
||||||
import user
|
|
||||||
code.interact(local=imported_objects)
|
code.interact(local=imported_objects)
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Command(NoArgsCommand):
|
||||||
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
|
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
|
||||||
|
|
||||||
manifest = SortedDict(
|
manifest = SortedDict(
|
||||||
(app_name, filter(model_installed, model_list))
|
(app_name, list(filter(model_installed, model_list)))
|
||||||
for app_name, model_list in all_models
|
for app_name, model_list in all_models
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import codecs
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -168,10 +169,10 @@ def custom_sql_for_model(model, style, connection):
|
||||||
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
|
os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
|
||||||
for sql_file in sql_files:
|
for sql_file in sql_files:
|
||||||
if os.path.exists(sql_file):
|
if os.path.exists(sql_file):
|
||||||
with open(sql_file, 'U') as fp:
|
with codecs.open(sql_file, 'U', encoding=settings.FILE_CHARSET) as fp:
|
||||||
# Some backends can't execute more than one SQL statement at a time,
|
# Some backends can't execute more than one SQL statement at a time,
|
||||||
# so split into separate statements.
|
# so split into separate statements.
|
||||||
output.extend(_split_statements(fp.read().decode(settings.FILE_CHARSET)))
|
output.extend(_split_statements(fp.read()))
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -13,7 +13,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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
Module for abstract serializer/unserializer base classes.
|
Module for abstract serializer/unserializer base classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -35,7 +33,7 @@ class Serializer(object):
|
||||||
"""
|
"""
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
self.stream = options.pop("stream", BytesIO())
|
self.stream = options.pop("stream", six.StringIO())
|
||||||
self.selected_fields = options.pop("fields", None)
|
self.selected_fields = options.pop("fields", None)
|
||||||
self.use_natural_keys = options.pop("use_natural_keys", False)
|
self.use_natural_keys = options.pop("use_natural_keys", False)
|
||||||
|
|
||||||
|
@ -125,7 +123,7 @@ class Deserializer(object):
|
||||||
"""
|
"""
|
||||||
self.options = options
|
self.options = options
|
||||||
if isinstance(stream_or_string, six.string_types):
|
if isinstance(stream_or_string, six.string_types):
|
||||||
self.stream = BytesIO(stream_or_string)
|
self.stream = six.StringIO(stream_or_string)
|
||||||
else:
|
else:
|
||||||
self.stream = stream_or_string
|
self.stream = stream_or_string
|
||||||
# hack to make sure that the models have all been loaded before
|
# hack to make sure that the models have all been loaded before
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -61,13 +60,12 @@ def Deserializer(stream_or_string, **options):
|
||||||
"""
|
"""
|
||||||
Deserialize a stream or string of JSON data.
|
Deserialize a stream or string of JSON data.
|
||||||
"""
|
"""
|
||||||
|
if not isinstance(stream_or_string, (bytes, six.string_types)):
|
||||||
|
stream_or_string = stream_or_string.read()
|
||||||
if isinstance(stream_or_string, bytes):
|
if isinstance(stream_or_string, bytes):
|
||||||
stream_or_string = stream_or_string.decode('utf-8')
|
stream_or_string = stream_or_string.decode('utf-8')
|
||||||
try:
|
try:
|
||||||
if isinstance(stream_or_string, six.string_types):
|
|
||||||
objects = json.loads(stream_or_string)
|
objects = json.loads(stream_or_string)
|
||||||
else:
|
|
||||||
objects = json.load(stream_or_string)
|
|
||||||
for obj in PythonDeserializer(objects, **options):
|
for obj in PythonDeserializer(objects, **options):
|
||||||
yield obj
|
yield obj
|
||||||
except GeneratorExit:
|
except GeneratorExit:
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ This is a simple server for use in testing or debugging Django apps. It hasn't
|
||||||
been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
|
been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
@ -71,12 +73,12 @@ class WSGIServerException(Exception):
|
||||||
|
|
||||||
|
|
||||||
class ServerHandler(simple_server.ServerHandler, object):
|
class ServerHandler(simple_server.ServerHandler, object):
|
||||||
error_status = "500 INTERNAL SERVER ERROR"
|
error_status = str("500 INTERNAL SERVER ERROR")
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
"""'write()' callable as specified by PEP 333"""
|
"""'write()' callable as specified by PEP 3333"""
|
||||||
|
|
||||||
assert isinstance(data, str), "write() argument must be string"
|
assert isinstance(data, bytes), "write() argument must be bytestring"
|
||||||
|
|
||||||
if not self.status:
|
if not self.status:
|
||||||
raise AssertionError("write() before start_response()")
|
raise AssertionError("write() before start_response()")
|
||||||
|
@ -200,7 +202,7 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
|
||||||
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
|
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
|
||||||
server_address = (addr, port)
|
server_address = (addr, port)
|
||||||
if threading:
|
if threading:
|
||||||
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, WSGIServer), {})
|
httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
|
||||||
else:
|
else:
|
||||||
httpd_cls = WSGIServer
|
httpd_cls = WSGIServer
|
||||||
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
|
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
|
||||||
|
|
|
@ -32,6 +32,9 @@ 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
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
@ -41,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 force_text, 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
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,11 +63,11 @@ class SignatureExpired(BadSignature):
|
||||||
|
|
||||||
|
|
||||||
def b64_encode(s):
|
def b64_encode(s):
|
||||||
return base64.urlsafe_b64encode(s).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(s + pad)
|
return base64.urlsafe_b64decode(s + pad)
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +117,7 @@ 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
|
||||||
|
@ -127,7 +130,7 @@ def dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer,
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -135,35 +138,40 @@ 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 = smart_bytes(
|
# TimestampSigner.unsign always returns unicode but base64 and zlib
|
||||||
TimestampSigner(key, salt=salt).unsign(s, max_age=max_age))
|
# 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):
|
||||||
value = smart_bytes(value)
|
value = force_str(value)
|
||||||
return '%s%s%s' % (value, self.sep, self.signature(value))
|
return str('%s%s%s') % (value, self.sep, self.signature(value))
|
||||||
|
|
||||||
def unsign(self, signed_value):
|
def unsign(self, signed_value):
|
||||||
signed_value = smart_bytes(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)
|
||||||
|
@ -178,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 = smart_bytes('%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_bytes
|
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
|
||||||
|
@ -89,18 +89,11 @@ def get_callable(lookup_view, can_fail=False):
|
||||||
"""
|
"""
|
||||||
if not callable(lookup_view):
|
if not callable(lookup_view):
|
||||||
mod_name, func_name = get_mod_func(lookup_view)
|
mod_name, func_name = get_mod_func(lookup_view)
|
||||||
|
if func_name == '':
|
||||||
|
return lookup_view
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if func_name != '':
|
mod = import_module(mod_name)
|
||||||
lookup_view = getattr(import_module(mod_name), func_name)
|
|
||||||
if not callable(lookup_view):
|
|
||||||
raise ViewDoesNotExist(
|
|
||||||
"Could not import %s.%s. View is not callable." %
|
|
||||||
(mod_name, func_name))
|
|
||||||
except AttributeError:
|
|
||||||
if not can_fail:
|
|
||||||
raise ViewDoesNotExist(
|
|
||||||
"Could not import %s. View does not exist in module %s." %
|
|
||||||
(lookup_view, mod_name))
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
parentmod, submod = get_mod_func(mod_name)
|
parentmod, submod = get_mod_func(mod_name)
|
||||||
if (not can_fail and submod != '' and
|
if (not can_fail and submod != '' and
|
||||||
|
@ -110,6 +103,18 @@ def get_callable(lookup_view, can_fail=False):
|
||||||
(lookup_view, mod_name))
|
(lookup_view, mod_name))
|
||||||
if not can_fail:
|
if not can_fail:
|
||||||
raise
|
raise
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
lookup_view = getattr(mod, func_name)
|
||||||
|
if not callable(lookup_view):
|
||||||
|
raise ViewDoesNotExist(
|
||||||
|
"Could not import %s.%s. View is not callable." %
|
||||||
|
(mod_name, func_name))
|
||||||
|
except AttributeError:
|
||||||
|
if not can_fail:
|
||||||
|
raise ViewDoesNotExist(
|
||||||
|
"Could not import %s. View does not exist in module %s." %
|
||||||
|
(lookup_view, mod_name))
|
||||||
return lookup_view
|
return lookup_view
|
||||||
get_callable = memoize(get_callable, _callable_cache, 1)
|
get_callable = memoize(get_callable, _callable_cache, 1)
|
||||||
|
|
||||||
|
@ -190,7 +195,7 @@ class RegexURLPattern(LocaleRegexProvider):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_bytes('<%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):
|
||||||
"""
|
"""
|
||||||
|
@ -240,7 +245,14 @@ class RegexURLResolver(LocaleRegexProvider):
|
||||||
self._app_dict = {}
|
self._app_dict = {}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_bytes('<%s %s (%s:%s) %s>' % (self.__class__.__name__, self.urlconf_name, self.app_name, self.namespace, self.regex.pattern))
|
if isinstance(self.urlconf_name, list) and len(self.urlconf_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))
|
||||||
|
|
||||||
def _populate(self):
|
def _populate(self):
|
||||||
lookups = MultiValueDict()
|
lookups = MultiValueDict()
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
@ -36,7 +36,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)
|
||||||
|
|
||||||
class URLValidator(RegexValidator):
|
class URLValidator(RegexValidator):
|
||||||
|
@ -44,7 +44,8 @@ class URLValidator(RegexValidator):
|
||||||
r'^(?:http|ftp)s?://' # http:// or https://
|
r'^(?:http|ftp)s?://' # http:// or https://
|
||||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
|
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
|
||||||
r'localhost|' #localhost...
|
r'localhost|' #localhost...
|
||||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
|
||||||
|
r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
|
||||||
r'(?::\d+)?' # optional port
|
r'(?::\d+)?' # optional port
|
||||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||||
|
|
||||||
|
@ -54,10 +55,10 @@ 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') # IDN -> ACE
|
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
|
||||||
except UnicodeError: # invalid domain part
|
except UnicodeError: # invalid domain part
|
||||||
raise e
|
raise e
|
||||||
url = urlunsplit((scheme, netloc, path, query, fragment))
|
url = urlunsplit((scheme, netloc, path, query, fragment))
|
||||||
|
@ -84,7 +85,7 @@ class EmailValidator(RegexValidator):
|
||||||
if value and '@' in value:
|
if value and '@' in value:
|
||||||
parts = value.split('@')
|
parts = value.split('@')
|
||||||
try:
|
try:
|
||||||
parts[-1] = parts[-1].encode('idna')
|
parts[-1] = parts[-1].encode('idna').decode('ascii')
|
||||||
except UnicodeError:
|
except UnicodeError:
|
||||||
raise e
|
raise e
|
||||||
super(EmailValidator, self).__call__('@'.join(parts))
|
super(EmailValidator, self).__call__('@'.join(parts))
|
||||||
|
@ -99,7 +100,7 @@ email_re = re.compile(
|
||||||
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
|
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
|
||||||
validate_email = EmailValidator(email_re, _('Enter a valid e-mail address.'), 'invalid')
|
validate_email = EmailValidator(email_re, _('Enter a valid e-mail address.'), 'invalid')
|
||||||
|
|
||||||
slug_re = re.compile(r'^[-\w]+$')
|
slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
|
||||||
validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
|
validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
|
||||||
|
|
||||||
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
|
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import thread
|
from django.utils.six.moves import _thread as thread
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from django.utils.six.moves import _dummy_thread as thread
|
from django.utils.six.moves import _dummy_thread as thread
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
@ -47,6 +47,8 @@ class BaseDatabaseWrapper(object):
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self == other
|
return not self == other
|
||||||
|
|
||||||
|
__hash__ = object.__hash__
|
||||||
|
|
||||||
def _commit(self):
|
def _commit(self):
|
||||||
if self.connection is not None:
|
if self.connection is not None:
|
||||||
return self.connection.commit()
|
return self.connection.commit()
|
||||||
|
@ -621,7 +623,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')
|
||||||
|
@ -630,7 +632,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):
|
||||||
"""
|
"""
|
||||||
|
@ -814,8 +816,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.
|
||||||
|
@ -892,19 +894,21 @@ class BaseDatabaseOperations(object):
|
||||||
return self.year_lookup_bounds(value)
|
return self.year_lookup_bounds(value)
|
||||||
|
|
||||||
def convert_values(self, value, field):
|
def convert_values(self, value, field):
|
||||||
"""Coerce the value returned by the database backend into a consistent type that
|
"""
|
||||||
is compatible with the field type.
|
Coerce the value returned by the database backend into a consistent type
|
||||||
|
that is compatible with the field type.
|
||||||
"""
|
"""
|
||||||
internal_type = field.get_internal_type()
|
internal_type = field.get_internal_type()
|
||||||
if internal_type == 'DecimalField':
|
if internal_type == 'DecimalField':
|
||||||
return value
|
return value
|
||||||
elif internal_type and internal_type.endswith('IntegerField') or internal_type == 'AutoField':
|
elif internal_type == 'FloatField':
|
||||||
|
return float(value)
|
||||||
|
elif (internal_type and (internal_type.endswith('IntegerField')
|
||||||
|
or internal_type == 'AutoField')):
|
||||||
return int(value)
|
return int(value)
|
||||||
elif internal_type in ('DateField', 'DateTimeField', 'TimeField'):
|
elif internal_type in ('DateField', 'DateTimeField', 'TimeField'):
|
||||||
return value
|
return value
|
||||||
# No field, or the field isn't known to be a decimal or integer
|
return value
|
||||||
# Default to a float
|
|
||||||
return float(value)
|
|
||||||
|
|
||||||
def check_aggregate_support(self, aggregate_func):
|
def check_aggregate_support(self, aggregate_func):
|
||||||
"""Check that the backend supports the provided aggregate
|
"""Check that the backend supports the provided aggregate
|
||||||
|
@ -1003,7 +1007,7 @@ class BaseDatabaseIntrospection(object):
|
||||||
for model in models.get_models(app):
|
for model in models.get_models(app):
|
||||||
if router.allow_syncdb(self.connection.alias, model):
|
if router.allow_syncdb(self.connection.alias, model):
|
||||||
all_models.append(model)
|
all_models.append(model)
|
||||||
tables = map(self.table_name_converter, tables)
|
tables = list(map(self.table_name_converter, tables))
|
||||||
return set([
|
return set([
|
||||||
m for m in all_models
|
m for m in all_models
|
||||||
if self.table_name_converter(m._meta.db_table) in tables
|
if self.table_name_converter(m._meta.db_table) in tables
|
||||||
|
|
|
@ -39,7 +39,7 @@ from django.db.backends.mysql.introspection import DatabaseIntrospection
|
||||||
from django.db.backends.mysql.validation import DatabaseValidation
|
from django.db.backends.mysql.validation import DatabaseValidation
|
||||||
from django.db.backends.mysql.schema import DatabaseSchemaEditor
|
from django.db.backends.mysql.schema import DatabaseSchemaEditor
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.safestring import SafeString, SafeUnicode
|
from django.utils.safestring import SafeBytes, SafeText
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ def adapt_datetime_with_timezone_support(value, conv):
|
||||||
# MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
|
# MySQLdb-1.2.1 returns TIME columns as timedelta -- they are more like
|
||||||
# timedelta in terms of actual behavior as they are signed and include days --
|
# timedelta in terms of actual behavior as they are signed and include days --
|
||||||
# and Django expects time, so we still need to override that. We also need to
|
# and Django expects time, so we still need to override that. We also need to
|
||||||
# add special handling for SafeUnicode and SafeString as MySQLdb's type
|
# add special handling for SafeText and SafeBytes as MySQLdb's type
|
||||||
# checking is too tight to catch those (see Django ticket #6052).
|
# checking is too tight to catch those (see Django ticket #6052).
|
||||||
# Finally, MySQLdb always returns naive datetime objects. However, when
|
# Finally, MySQLdb always returns naive datetime objects. However, when
|
||||||
# timezone support is active, Django expects timezone-aware datetime objects.
|
# timezone support is active, Django expects timezone-aware datetime objects.
|
||||||
|
@ -403,8 +403,8 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
kwargs['client_flag'] = CLIENT.FOUND_ROWS
|
kwargs['client_flag'] = CLIENT.FOUND_ROWS
|
||||||
kwargs.update(settings_dict['OPTIONS'])
|
kwargs.update(settings_dict['OPTIONS'])
|
||||||
self.connection = Database.connect(**kwargs)
|
self.connection = Database.connect(**kwargs)
|
||||||
self.connection.encoders[SafeUnicode] = self.connection.encoders[six.text_type]
|
self.connection.encoders[SafeText] = self.connection.encoders[six.text_type]
|
||||||
self.connection.encoders[SafeString] = self.connection.encoders[bytes]
|
self.connection.encoders[SafeBytes] = self.connection.encoders[bytes]
|
||||||
connection_created.send(sender=self.__class__, connection=self)
|
connection_created.send(sender=self.__class__, connection=self)
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
if new_connection:
|
if new_connection:
|
||||||
|
|
|
@ -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.keys())
|
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):
|
||||||
|
@ -221,6 +219,9 @@ WHEN (new.%(col_name)s IS NULL)
|
||||||
def last_executed_query(self, cursor, sql, params):
|
def last_executed_query(self, cursor, sql, params):
|
||||||
# http://cx-oracle.sourceforge.net/html/cursor.html#Cursor.statement
|
# http://cx-oracle.sourceforge.net/html/cursor.html#Cursor.statement
|
||||||
# The DB API definition does not define this attribute.
|
# The DB API definition does not define this attribute.
|
||||||
|
if six.PY3:
|
||||||
|
return cursor.statement
|
||||||
|
else:
|
||||||
return cursor.statement.decode("utf-8")
|
return cursor.statement.decode("utf-8")
|
||||||
|
|
||||||
def last_insert_id(self, cursor, table_name, pk_name):
|
def last_insert_id(self, cursor, table_name, pk_name):
|
||||||
|
@ -594,10 +595,16 @@ class OracleParam(object):
|
||||||
param = timezone.make_aware(param, default_timezone)
|
param = timezone.make_aware(param, default_timezone)
|
||||||
param = param.astimezone(timezone.utc).replace(tzinfo=None)
|
param = param.astimezone(timezone.utc).replace(tzinfo=None)
|
||||||
|
|
||||||
|
# Oracle doesn't recognize True and False correctly in Python 3.
|
||||||
|
# The conversion done below works both in 2 and 3.
|
||||||
|
if param is True:
|
||||||
|
param = "1"
|
||||||
|
elif param is False:
|
||||||
|
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.
|
||||||
|
@ -676,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:
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
from django.db.models.sql import compiler
|
from django.db.models.sql import compiler
|
||||||
|
# The izip_longest was renamed to zip_longest in py3
|
||||||
|
try:
|
||||||
|
from itertools import zip_longest
|
||||||
|
except ImportError:
|
||||||
|
from itertools import izip_longest as zip_longest
|
||||||
|
|
||||||
|
|
||||||
class SQLCompiler(compiler.SQLCompiler):
|
class SQLCompiler(compiler.SQLCompiler):
|
||||||
|
@ -10,10 +15,10 @@ class SQLCompiler(compiler.SQLCompiler):
|
||||||
rn_offset = 1
|
rn_offset = 1
|
||||||
else:
|
else:
|
||||||
rn_offset = 0
|
rn_offset = 0
|
||||||
index_start = rn_offset + len(self.query.extra_select.keys())
|
index_start = rn_offset + len(self.query.extra_select)
|
||||||
values = [self.query.convert_values(v, None, connection=self.connection)
|
values = [self.query.convert_values(v, None, connection=self.connection)
|
||||||
for v in row[rn_offset:index_start]]
|
for v in row[rn_offset:index_start]]
|
||||||
for value, field in map(None, row[index_start:], fields):
|
for value, field in zip_longest(row[index_start:], fields):
|
||||||
values.append(self.query.convert_values(value, field, connection=self.connection))
|
values.append(self.query.convert_values(value, field, connection=self.connection))
|
||||||
return tuple(values)
|
return tuple(values)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from django.db.backends.postgresql_psycopg2.version import get_version
|
||||||
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
from django.db.backends.postgresql_psycopg2.introspection import DatabaseIntrospection
|
||||||
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
|
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
from django.utils.safestring import SafeUnicode, SafeString
|
from django.utils.safestring import SafeText, SafeBytes
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.timezone import utc
|
from django.utils.timezone import utc
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ DatabaseError = Database.DatabaseError
|
||||||
IntegrityError = Database.IntegrityError
|
IntegrityError = Database.IntegrityError
|
||||||
|
|
||||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
psycopg2.extensions.register_adapter(SafeString, psycopg2.extensions.QuotedString)
|
psycopg2.extensions.register_adapter(SafeBytes, psycopg2.extensions.QuotedString)
|
||||||
psycopg2.extensions.register_adapter(SafeUnicode, psycopg2.extensions.QuotedString)
|
psycopg2.extensions.register_adapter(SafeText, psycopg2.extensions.QuotedString)
|
||||||
|
|
||||||
logger = getLogger('django.db.backends')
|
logger = getLogger('django.db.backends')
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ 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):
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue