Merge branch 'master' into schema-alteration
This commit is contained in:
commit
184cf9ab79
|
@ -158,7 +158,7 @@ class UserSettingsHolder(BaseSettings):
|
||||||
return getattr(self.default_settings, name)
|
return getattr(self.default_settings, name)
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return self.__dict__.keys() + dir(self.default_settings)
|
return list(self.__dict__) + dir(self.default_settings)
|
||||||
|
|
||||||
# For Python < 2.6:
|
# For Python < 2.6:
|
||||||
__members__ = property(lambda self: self.__dir__())
|
__members__ = property(lambda self: self.__dir__())
|
||||||
|
|
|
@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||||
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
||||||
DATE_FORMAT = 'j. E Y'
|
DATE_FORMAT = 'j. E Y'
|
||||||
TIME_FORMAT = 'G.i.s'
|
TIME_FORMAT = 'G.i.s'
|
||||||
# DATETIME_FORMAT =
|
DATETIME_FORMAT = r'j. E Y \k\e\l\l\o G.i.s'
|
||||||
YEAR_MONTH_FORMAT = 'F Y'
|
YEAR_MONTH_FORMAT = 'F Y'
|
||||||
MONTH_DAY_FORMAT = 'j. F'
|
MONTH_DAY_FORMAT = 'j. F'
|
||||||
SHORT_DATE_FORMAT = 'j.n.Y'
|
SHORT_DATE_FORMAT = 'j.n.Y'
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
# This file is distributed under the same license as the Django package.
|
# This file is distributed under the same license as the Django package.
|
||||||
#
|
#
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# The *_FORMAT strings use the Django date format syntax,
|
# The *_FORMAT strings use the Django date format syntax,
|
||||||
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
||||||
DATE_FORMAT = 'd F Y'
|
DATE_FORMAT = r'j \d\e F \d\e Y'
|
||||||
TIME_FORMAT = 'H:i:s'
|
TIME_FORMAT = 'H:i:s'
|
||||||
# DATETIME_FORMAT =
|
DATETIME_FORMAT = r'j \d\e F \d\e Y \á\s H:i'
|
||||||
YEAR_MONTH_FORMAT = 'F Y'
|
YEAR_MONTH_FORMAT = r'F \d\e Y'
|
||||||
MONTH_DAY_FORMAT = 'j F'
|
MONTH_DAY_FORMAT = r'j \d\e F'
|
||||||
SHORT_DATE_FORMAT = 'j M, Y'
|
SHORT_DATE_FORMAT = 'd-m-Y'
|
||||||
# SHORT_DATETIME_FORMAT =
|
SHORT_DATETIME_FORMAT = 'd-m-Y, H:i'
|
||||||
# FIRST_DAY_OF_WEEK =
|
FIRST_DAY_OF_WEEK = 1 # Monday
|
||||||
|
|
||||||
# The *_INPUT_FORMATS strings use the Python strftime format syntax,
|
# The *_INPUT_FORMATS strings use the Python strftime format syntax,
|
||||||
# see http://docs.python.org/library/datetime.html#strftime-strptime-behavior
|
# see http://docs.python.org/library/datetime.html#strftime-strptime-behavior
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import patterns
|
from django.conf.urls import patterns, url
|
||||||
from django.core.urlresolvers import LocaleRegexURLResolver
|
from django.core.urlresolvers import LocaleRegexURLResolver
|
||||||
|
|
||||||
def i18n_patterns(prefix, *args):
|
def i18n_patterns(prefix, *args):
|
||||||
|
@ -16,5 +16,5 @@ def i18n_patterns(prefix, *args):
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^setlang/$', 'django.views.i18n.set_language'),
|
url(r'^setlang/$', 'django.views.i18n.set_language', name='set_language'),
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.admin import helpers
|
||||||
from django.contrib.admin.util import get_deleted_objects, model_ngettext
|
from django.contrib.admin.util import get_deleted_objects, model_ngettext
|
||||||
from django.db import router
|
from django.db import router
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||||
|
|
||||||
def delete_selected(modeladmin, request, queryset):
|
def delete_selected(modeladmin, request, queryset):
|
||||||
|
@ -42,7 +42,7 @@ def delete_selected(modeladmin, request, queryset):
|
||||||
n = queryset.count()
|
n = queryset.count()
|
||||||
if n:
|
if n:
|
||||||
for obj in queryset:
|
for obj in queryset:
|
||||||
obj_display = force_unicode(obj)
|
obj_display = force_text(obj)
|
||||||
modeladmin.log_deletion(request, obj, obj_display)
|
modeladmin.log_deletion(request, obj, obj_display)
|
||||||
queryset.delete()
|
queryset.delete()
|
||||||
modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
|
modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
|
||||||
|
@ -52,9 +52,9 @@ def delete_selected(modeladmin, request, queryset):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if len(queryset) == 1:
|
if len(queryset) == 1:
|
||||||
objects_name = force_unicode(opts.verbose_name)
|
objects_name = force_text(opts.verbose_name)
|
||||||
else:
|
else:
|
||||||
objects_name = force_unicode(opts.verbose_name_plural)
|
objects_name = force_text(opts.verbose_name_plural)
|
||||||
|
|
||||||
if perms_needed or protected:
|
if perms_needed or protected:
|
||||||
title = _("Cannot delete %(name)s") % {"name": objects_name}
|
title = _("Cannot delete %(name)s") % {"name": objects_name}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import datetime
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
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
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ class RelatedFieldListFilter(FieldListFilter):
|
||||||
}
|
}
|
||||||
for pk_val, val in self.lookup_choices:
|
for pk_val, val in self.lookup_choices:
|
||||||
yield {
|
yield {
|
||||||
'selected': self.lookup_val == smart_unicode(pk_val),
|
'selected': self.lookup_val == smart_text(pk_val),
|
||||||
'query_string': cl.get_query_string({
|
'query_string': cl.get_query_string({
|
||||||
self.lookup_kwarg: pk_val,
|
self.lookup_kwarg: pk_val,
|
||||||
}, [self.lookup_kwarg_isnull]),
|
}, [self.lookup_kwarg_isnull]),
|
||||||
|
@ -272,7 +272,7 @@ class ChoicesFieldListFilter(FieldListFilter):
|
||||||
}
|
}
|
||||||
for lookup, title in self.field.flatchoices:
|
for lookup, title in self.field.flatchoices:
|
||||||
yield {
|
yield {
|
||||||
'selected': smart_unicode(lookup) == self.lookup_val,
|
'selected': smart_text(lookup) == self.lookup_val,
|
||||||
'query_string': cl.get_query_string({
|
'query_string': cl.get_query_string({
|
||||||
self.lookup_kwarg: lookup}),
|
self.lookup_kwarg: lookup}),
|
||||||
'display': title,
|
'display': title,
|
||||||
|
@ -381,7 +381,7 @@ class AllValuesFieldListFilter(FieldListFilter):
|
||||||
if val is None:
|
if val is None:
|
||||||
include_none = True
|
include_none = True
|
||||||
continue
|
continue
|
||||||
val = smart_unicode(val)
|
val = smart_text(val)
|
||||||
yield {
|
yield {
|
||||||
'selected': self.lookup_val == val,
|
'selected': self.lookup_val == val,
|
||||||
'query_string': cl.get_query_string({
|
'query_string': cl.get_query_string({
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models.fields.related import ManyToManyRel
|
from django.db.models.fields.related import ManyToManyRel
|
||||||
from django.forms.util import flatatt
|
from django.forms.util import flatatt
|
||||||
from django.template.defaultfilters import capfirst
|
from django.template.defaultfilters import capfirst
|
||||||
from django.utils.encoding import force_unicode, smart_unicode
|
from django.utils.encoding import force_text, smart_text
|
||||||
from django.utils.html import conditional_escape, format_html
|
from django.utils.html import conditional_escape, format_html
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -94,7 +94,7 @@ class Fieldset(object):
|
||||||
class Fieldline(object):
|
class Fieldline(object):
|
||||||
def __init__(self, form, field, readonly_fields=None, model_admin=None):
|
def __init__(self, form, field, readonly_fields=None, model_admin=None):
|
||||||
self.form = form # A django.forms.Form instance
|
self.form = form # A django.forms.Form instance
|
||||||
if not hasattr(field, "__iter__"):
|
if not hasattr(field, "__iter__") or isinstance(field, six.text_type):
|
||||||
self.fields = [field]
|
self.fields = [field]
|
||||||
else:
|
else:
|
||||||
self.fields = field
|
self.fields = field
|
||||||
|
@ -122,7 +122,7 @@ class AdminField(object):
|
||||||
|
|
||||||
def label_tag(self):
|
def label_tag(self):
|
||||||
classes = []
|
classes = []
|
||||||
contents = conditional_escape(force_unicode(self.field.label))
|
contents = conditional_escape(force_text(self.field.label))
|
||||||
if self.is_checkbox:
|
if self.is_checkbox:
|
||||||
classes.append('vCheckboxLabel')
|
classes.append('vCheckboxLabel')
|
||||||
else:
|
else:
|
||||||
|
@ -166,7 +166,7 @@ class AdminReadonlyField(object):
|
||||||
label = self.field['label']
|
label = self.field['label']
|
||||||
return format_html('<label{0}>{1}:</label>',
|
return format_html('<label{0}>{1}:</label>',
|
||||||
flatatt(attrs),
|
flatatt(attrs),
|
||||||
capfirst(force_unicode(label)))
|
capfirst(force_text(label)))
|
||||||
|
|
||||||
def contents(self):
|
def contents(self):
|
||||||
from django.contrib.admin.templatetags.admin_list import _boolean_icon
|
from django.contrib.admin.templatetags.admin_list import _boolean_icon
|
||||||
|
@ -182,7 +182,7 @@ class AdminReadonlyField(object):
|
||||||
if boolean:
|
if boolean:
|
||||||
result_repr = _boolean_icon(value)
|
result_repr = _boolean_icon(value)
|
||||||
else:
|
else:
|
||||||
result_repr = smart_unicode(value)
|
result_repr = smart_text(value)
|
||||||
if getattr(attr, "allow_tags", False):
|
if getattr(attr, "allow_tags", False):
|
||||||
result_repr = mark_safe(result_repr)
|
result_repr = mark_safe(result_repr)
|
||||||
else:
|
else:
|
||||||
|
@ -325,11 +325,11 @@ class AdminErrorList(forms.util.ErrorList):
|
||||||
"""
|
"""
|
||||||
def __init__(self, form, inline_formsets):
|
def __init__(self, form, inline_formsets):
|
||||||
if form.is_bound:
|
if form.is_bound:
|
||||||
self.extend(form.errors.values())
|
self.extend(list(six.itervalues(form.errors)))
|
||||||
for inline_formset in inline_formsets:
|
for inline_formset in inline_formsets:
|
||||||
self.extend(inline_formset.non_form_errors())
|
self.extend(inline_formset.non_form_errors())
|
||||||
for errors_in_inline_form in inline_formset.errors:
|
for errors_in_inline_form in inline_formset.errors:
|
||||||
self.extend(errors_in_inline_form.values())
|
self.extend(list(six.itervalues(errors_in_inline_form)))
|
||||||
|
|
||||||
def normalize_fieldsets(fieldsets):
|
def normalize_fieldsets(fieldsets):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.auth.models import User
|
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_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
ADDITION = 1
|
ADDITION = 1
|
||||||
CHANGE = 2
|
CHANGE = 2
|
||||||
|
@ -13,7 +13,7 @@ DELETION = 3
|
||||||
|
|
||||||
class LogEntryManager(models.Manager):
|
class LogEntryManager(models.Manager):
|
||||||
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
|
def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
|
||||||
e = self.model(None, None, user_id, content_type_id, smart_unicode(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()
|
||||||
|
|
||||||
class LogEntry(models.Model):
|
class LogEntry(models.Model):
|
||||||
|
@ -34,7 +34,7 @@ class LogEntry(models.Model):
|
||||||
ordering = ('-action_time',)
|
ordering = ('-action_time',)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_unicode(self.action_time)
|
return smart_text(self.action_time)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if self.action_flag == ADDITION:
|
if self.action_flag == ADDITION:
|
||||||
|
|
|
@ -28,7 +28,7 @@ from django.utils import six
|
||||||
from django.utils.text import capfirst, get_text_list
|
from django.utils.text import capfirst, get_text_list
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ungettext
|
from django.utils.translation import ungettext
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
HORIZONTAL, VERTICAL = 1, 2
|
HORIZONTAL, VERTICAL = 1, 2
|
||||||
# returns the <ul> class for a given radio_admin field
|
# returns the <ul> class for a given radio_admin field
|
||||||
|
@ -425,7 +425,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
if self.declared_fieldsets:
|
if self.declared_fieldsets:
|
||||||
return self.declared_fieldsets
|
return self.declared_fieldsets
|
||||||
form = self.get_form(request, obj)
|
form = self.get_form(request, obj)
|
||||||
fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj))
|
fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj))
|
||||||
return [(None, {'fields': fields})]
|
return [(None, {'fields': fields})]
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
|
@ -520,7 +520,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
user_id = request.user.pk,
|
user_id = request.user.pk,
|
||||||
content_type_id = ContentType.objects.get_for_model(object).pk,
|
content_type_id = ContentType.objects.get_for_model(object).pk,
|
||||||
object_id = object.pk,
|
object_id = object.pk,
|
||||||
object_repr = force_unicode(object),
|
object_repr = force_text(object),
|
||||||
action_flag = ADDITION
|
action_flag = ADDITION
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -535,7 +535,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
user_id = request.user.pk,
|
user_id = request.user.pk,
|
||||||
content_type_id = ContentType.objects.get_for_model(object).pk,
|
content_type_id = ContentType.objects.get_for_model(object).pk,
|
||||||
object_id = object.pk,
|
object_id = object.pk,
|
||||||
object_repr = force_unicode(object),
|
object_repr = force_text(object),
|
||||||
action_flag = CHANGE,
|
action_flag = CHANGE,
|
||||||
change_message = message
|
change_message = message
|
||||||
)
|
)
|
||||||
|
@ -560,7 +560,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
"""
|
"""
|
||||||
A list_display column containing a checkbox widget.
|
A list_display column containing a checkbox widget.
|
||||||
"""
|
"""
|
||||||
return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_unicode(obj.pk))
|
return helpers.checkbox.render(helpers.ACTION_CHECKBOX_NAME, force_text(obj.pk))
|
||||||
action_checkbox.short_description = mark_safe('<input type="checkbox" id="action-toggle" />')
|
action_checkbox.short_description = mark_safe('<input type="checkbox" id="action-toggle" />')
|
||||||
action_checkbox.allow_tags = True
|
action_checkbox.allow_tags = True
|
||||||
|
|
||||||
|
@ -608,7 +608,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
tuple (name, description).
|
tuple (name, description).
|
||||||
"""
|
"""
|
||||||
choices = [] + default_choices
|
choices = [] + default_choices
|
||||||
for func, name, description in self.get_actions(request).itervalues():
|
for func, name, description in six.itervalues(self.get_actions(request)):
|
||||||
choice = (name, description % model_format_dict(self.opts))
|
choice = (name, description % model_format_dict(self.opts))
|
||||||
choices.append(choice)
|
choices.append(choice)
|
||||||
return choices
|
return choices
|
||||||
|
@ -674,17 +674,17 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
for formset in formsets:
|
for formset in formsets:
|
||||||
for added_object in formset.new_objects:
|
for added_object in formset.new_objects:
|
||||||
change_message.append(_('Added %(name)s "%(object)s".')
|
change_message.append(_('Added %(name)s "%(object)s".')
|
||||||
% {'name': force_unicode(added_object._meta.verbose_name),
|
% {'name': force_text(added_object._meta.verbose_name),
|
||||||
'object': force_unicode(added_object)})
|
'object': force_text(added_object)})
|
||||||
for changed_object, changed_fields in formset.changed_objects:
|
for changed_object, changed_fields in formset.changed_objects:
|
||||||
change_message.append(_('Changed %(list)s for %(name)s "%(object)s".')
|
change_message.append(_('Changed %(list)s for %(name)s "%(object)s".')
|
||||||
% {'list': get_text_list(changed_fields, _('and')),
|
% {'list': get_text_list(changed_fields, _('and')),
|
||||||
'name': force_unicode(changed_object._meta.verbose_name),
|
'name': force_text(changed_object._meta.verbose_name),
|
||||||
'object': force_unicode(changed_object)})
|
'object': force_text(changed_object)})
|
||||||
for deleted_object in formset.deleted_objects:
|
for deleted_object in formset.deleted_objects:
|
||||||
change_message.append(_('Deleted %(name)s "%(object)s".')
|
change_message.append(_('Deleted %(name)s "%(object)s".')
|
||||||
% {'name': force_unicode(deleted_object._meta.verbose_name),
|
% {'name': force_text(deleted_object._meta.verbose_name),
|
||||||
'object': force_unicode(deleted_object)})
|
'object': force_text(deleted_object)})
|
||||||
change_message = ' '.join(change_message)
|
change_message = ' '.join(change_message)
|
||||||
return change_message or _('No fields changed.')
|
return change_message or _('No fields changed.')
|
||||||
|
|
||||||
|
@ -769,7 +769,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
opts = obj._meta
|
opts = obj._meta
|
||||||
pk_value = obj._get_pk_val()
|
pk_value = obj._get_pk_val()
|
||||||
|
|
||||||
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
|
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_text(opts.verbose_name), 'obj': force_text(obj)}
|
||||||
# Here, we distinguish between different save types by checking for
|
# Here, we distinguish between different save types by checking for
|
||||||
# the presence of keys in request.POST.
|
# the presence of keys in request.POST.
|
||||||
if "_continue" in request.POST:
|
if "_continue" in request.POST:
|
||||||
|
@ -782,10 +782,10 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
'<!DOCTYPE html><html><head><title></title></head><body>'
|
'<!DOCTYPE html><html><head><title></title></head><body>'
|
||||||
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' % \
|
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' % \
|
||||||
# escape() calls force_unicode.
|
# escape() calls force_text.
|
||||||
(escape(pk_value), escapejs(obj)))
|
(escape(pk_value), escapejs(obj)))
|
||||||
elif "_addanother" in request.POST:
|
elif "_addanother" in request.POST:
|
||||||
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
|
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_text(opts.verbose_name)))
|
||||||
return HttpResponseRedirect(request.path)
|
return HttpResponseRedirect(request.path)
|
||||||
else:
|
else:
|
||||||
self.message_user(request, msg)
|
self.message_user(request, msg)
|
||||||
|
@ -819,7 +819,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
|
|
||||||
pk_value = obj._get_pk_val()
|
pk_value = obj._get_pk_val()
|
||||||
|
|
||||||
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(verbose_name), 'obj': force_unicode(obj)}
|
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_text(verbose_name), 'obj': force_text(obj)}
|
||||||
if "_continue" in request.POST:
|
if "_continue" in request.POST:
|
||||||
self.message_user(request, msg + ' ' + _("You may edit it again below."))
|
self.message_user(request, msg + ' ' + _("You may edit it again below."))
|
||||||
if "_popup" in request.REQUEST:
|
if "_popup" in request.REQUEST:
|
||||||
|
@ -827,14 +827,14 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
else:
|
else:
|
||||||
return HttpResponseRedirect(request.path)
|
return HttpResponseRedirect(request.path)
|
||||||
elif "_saveasnew" in request.POST:
|
elif "_saveasnew" in request.POST:
|
||||||
msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj}
|
msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_text(verbose_name), 'obj': obj}
|
||||||
self.message_user(request, msg)
|
self.message_user(request, msg)
|
||||||
return HttpResponseRedirect(reverse('admin:%s_%s_change' %
|
return HttpResponseRedirect(reverse('admin:%s_%s_change' %
|
||||||
(opts.app_label, module_name),
|
(opts.app_label, module_name),
|
||||||
args=(pk_value,),
|
args=(pk_value,),
|
||||||
current_app=self.admin_site.name))
|
current_app=self.admin_site.name))
|
||||||
elif "_addanother" in request.POST:
|
elif "_addanother" in request.POST:
|
||||||
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(verbose_name)))
|
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_text(verbose_name)))
|
||||||
return HttpResponseRedirect(reverse('admin:%s_%s_add' %
|
return HttpResponseRedirect(reverse('admin:%s_%s_add' %
|
||||||
(opts.app_label, module_name),
|
(opts.app_label, module_name),
|
||||||
current_app=self.admin_site.name))
|
current_app=self.admin_site.name))
|
||||||
|
@ -995,7 +995,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
media = media + inline_admin_formset.media
|
media = media + inline_admin_formset.media
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'title': _('Add %s') % force_unicode(opts.verbose_name),
|
'title': _('Add %s') % force_text(opts.verbose_name),
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
'is_popup': "_popup" in request.REQUEST,
|
'is_popup': "_popup" in request.REQUEST,
|
||||||
'media': media,
|
'media': media,
|
||||||
|
@ -1019,7 +1019,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)})
|
raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_text(opts.verbose_name), 'key': escape(object_id)})
|
||||||
|
|
||||||
if request.method == 'POST' and "_saveasnew" in request.POST:
|
if request.method == 'POST' and "_saveasnew" in request.POST:
|
||||||
return self.add_view(request, form_url=reverse('admin:%s_%s_add' %
|
return self.add_view(request, form_url=reverse('admin:%s_%s_add' %
|
||||||
|
@ -1085,7 +1085,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
media = media + inline_admin_formset.media
|
media = media + inline_admin_formset.media
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'title': _('Change %s') % force_unicode(opts.verbose_name),
|
'title': _('Change %s') % force_text(opts.verbose_name),
|
||||||
'adminform': adminForm,
|
'adminform': adminForm,
|
||||||
'object_id': object_id,
|
'object_id': object_id,
|
||||||
'original': obj,
|
'original': obj,
|
||||||
|
@ -1194,14 +1194,14 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
|
|
||||||
if changecount:
|
if changecount:
|
||||||
if changecount == 1:
|
if changecount == 1:
|
||||||
name = force_unicode(opts.verbose_name)
|
name = force_text(opts.verbose_name)
|
||||||
else:
|
else:
|
||||||
name = force_unicode(opts.verbose_name_plural)
|
name = force_text(opts.verbose_name_plural)
|
||||||
msg = ungettext("%(count)s %(name)s was changed successfully.",
|
msg = ungettext("%(count)s %(name)s was changed successfully.",
|
||||||
"%(count)s %(name)s were changed successfully.",
|
"%(count)s %(name)s were changed successfully.",
|
||||||
changecount) % {'count': changecount,
|
changecount) % {'count': changecount,
|
||||||
'name': name,
|
'name': name,
|
||||||
'obj': force_unicode(obj)}
|
'obj': force_text(obj)}
|
||||||
self.message_user(request, msg)
|
self.message_user(request, msg)
|
||||||
|
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
@ -1228,7 +1228,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
'All %(total_count)s selected', cl.result_count)
|
'All %(total_count)s selected', cl.result_count)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'module_name': force_unicode(opts.verbose_name_plural),
|
'module_name': force_text(opts.verbose_name_plural),
|
||||||
'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
|
'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
|
||||||
'selection_note_all': selection_note_all % {'total_count': cl.result_count},
|
'selection_note_all': selection_note_all % {'total_count': cl.result_count},
|
||||||
'title': cl.title,
|
'title': cl.title,
|
||||||
|
@ -1263,7 +1263,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)})
|
raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_text(opts.verbose_name), 'key': escape(object_id)})
|
||||||
|
|
||||||
using = router.db_for_write(self.model)
|
using = router.db_for_write(self.model)
|
||||||
|
|
||||||
|
@ -1275,11 +1275,11 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
if request.POST: # The user has already confirmed the deletion.
|
if request.POST: # The user has already confirmed the deletion.
|
||||||
if perms_needed:
|
if perms_needed:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
obj_display = force_unicode(obj)
|
obj_display = force_text(obj)
|
||||||
self.log_deletion(request, obj, obj_display)
|
self.log_deletion(request, obj, obj_display)
|
||||||
self.delete_model(request, obj)
|
self.delete_model(request, obj)
|
||||||
|
|
||||||
self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)})
|
self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_text(opts.verbose_name), 'obj': force_text(obj_display)})
|
||||||
|
|
||||||
if not self.has_change_permission(request, None):
|
if not self.has_change_permission(request, None):
|
||||||
return HttpResponseRedirect(reverse('admin:index',
|
return HttpResponseRedirect(reverse('admin:index',
|
||||||
|
@ -1288,7 +1288,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
(opts.app_label, opts.module_name),
|
(opts.app_label, opts.module_name),
|
||||||
current_app=self.admin_site.name))
|
current_app=self.admin_site.name))
|
||||||
|
|
||||||
object_name = force_unicode(opts.verbose_name)
|
object_name = force_text(opts.verbose_name)
|
||||||
|
|
||||||
if perms_needed or protected:
|
if perms_needed or protected:
|
||||||
title = _("Cannot delete %(name)s") % {"name": object_name}
|
title = _("Cannot delete %(name)s") % {"name": object_name}
|
||||||
|
@ -1326,9 +1326,9 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
# If no history was found, see whether this object even exists.
|
# If no history was found, see whether this object even exists.
|
||||||
obj = get_object_or_404(model, pk=unquote(object_id))
|
obj = get_object_or_404(model, pk=unquote(object_id))
|
||||||
context = {
|
context = {
|
||||||
'title': _('Change history: %s') % force_unicode(obj),
|
'title': _('Change history: %s') % force_text(obj),
|
||||||
'action_list': action_list,
|
'action_list': action_list,
|
||||||
'module_name': capfirst(force_unicode(opts.verbose_name_plural)),
|
'module_name': capfirst(force_text(opts.verbose_name_plural)),
|
||||||
'object': obj,
|
'object': obj,
|
||||||
'app_label': app_label,
|
'app_label': app_label,
|
||||||
'opts': opts,
|
'opts': opts,
|
||||||
|
@ -1415,7 +1415,7 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
if self.declared_fieldsets:
|
if self.declared_fieldsets:
|
||||||
return self.declared_fieldsets
|
return self.declared_fieldsets
|
||||||
form = self.get_formset(request, obj).form
|
form = self.get_formset(request, obj).form
|
||||||
fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj))
|
fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj))
|
||||||
return [(None, {'fields': fields})]
|
return [(None, {'fields': fields})]
|
||||||
|
|
||||||
def queryset(self, request):
|
def queryset(self, request):
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils import six
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
|
@ -133,7 +134,7 @@ class AdminSite(object):
|
||||||
"""
|
"""
|
||||||
Get all the enabled actions as an iterable of (name, func).
|
Get all the enabled actions as an iterable of (name, func).
|
||||||
"""
|
"""
|
||||||
return self._actions.iteritems()
|
return six.iteritems(self._actions)
|
||||||
|
|
||||||
def has_permission(self, request):
|
def has_permission(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -239,7 +240,7 @@ class AdminSite(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add in each model's views.
|
# Add in each model's views.
|
||||||
for model, model_admin in self._registry.iteritems():
|
for model, model_admin in six.iteritems(self._registry):
|
||||||
urlpatterns += patterns('',
|
urlpatterns += patterns('',
|
||||||
url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name),
|
url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name),
|
||||||
include(model_admin.urls))
|
include(model_admin.urls))
|
||||||
|
@ -370,7 +371,7 @@ class AdminSite(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sort the apps alphabetically.
|
# Sort the apps alphabetically.
|
||||||
app_list = app_dict.values()
|
app_list = list(six.itervalues(app_dict))
|
||||||
app_list.sort(key=lambda x: x['name'])
|
app_list.sort(key=lambda x: x['name'])
|
||||||
|
|
||||||
# Sort the models alphabetically within each app.
|
# Sort the models alphabetically within each app.
|
||||||
|
|
|
@ -12,9 +12,10 @@ from django.db import models
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils import six
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.encoding import smart_unicode, force_unicode
|
from django.utils.encoding import smart_text, force_text
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.template.context import Context
|
from django.template.context import Context
|
||||||
|
@ -125,7 +126,7 @@ def result_headers(cl):
|
||||||
if i in ordering_field_columns:
|
if i in ordering_field_columns:
|
||||||
sorted = True
|
sorted = True
|
||||||
order_type = ordering_field_columns.get(i).lower()
|
order_type = ordering_field_columns.get(i).lower()
|
||||||
sort_priority = ordering_field_columns.keys().index(i) + 1
|
sort_priority = list(ordering_field_columns).index(i) + 1
|
||||||
th_classes.append('sorted %sending' % order_type)
|
th_classes.append('sorted %sending' % order_type)
|
||||||
new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type]
|
new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type]
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ def items_for_result(cl, result, form):
|
||||||
result_repr = display_for_field(value, f)
|
result_repr = display_for_field(value, f)
|
||||||
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
|
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
|
||||||
row_class = mark_safe(' class="nowrap"')
|
row_class = mark_safe(' class="nowrap"')
|
||||||
if force_unicode(result_repr) == '':
|
if force_text(result_repr) == '':
|
||||||
result_repr = mark_safe(' ')
|
result_repr = mark_safe(' ')
|
||||||
# If list_display_links not defined, add the link tag to the first field
|
# If list_display_links not defined, add the link tag to the first field
|
||||||
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
|
if (first and not cl.list_display_links) or field_name in cl.list_display_links:
|
||||||
|
@ -223,7 +224,7 @@ def items_for_result(cl, result, form):
|
||||||
else:
|
else:
|
||||||
attr = pk
|
attr = pk
|
||||||
value = result.serializable_value(attr)
|
value = result.serializable_value(attr)
|
||||||
result_id = repr(force_unicode(value))[1:]
|
result_id = repr(force_text(value))[1:]
|
||||||
yield format_html('<{0}{1}><a href="{2}"{3}>{4}</a></{5}>',
|
yield format_html('<{0}{1}><a href="{2}"{3}>{4}</a></{5}>',
|
||||||
table_tag,
|
table_tag,
|
||||||
row_class,
|
row_class,
|
||||||
|
@ -240,10 +241,10 @@ def items_for_result(cl, result, form):
|
||||||
field_name == cl.model._meta.pk.name and
|
field_name == cl.model._meta.pk.name and
|
||||||
form[cl.model._meta.pk.name].is_hidden)):
|
form[cl.model._meta.pk.name].is_hidden)):
|
||||||
bf = form[field_name]
|
bf = form[field_name]
|
||||||
result_repr = mark_safe(force_unicode(bf.errors) + force_unicode(bf))
|
result_repr = mark_safe(force_text(bf.errors) + force_text(bf))
|
||||||
yield format_html('<td{0}>{1}</td>', row_class, result_repr)
|
yield format_html('<td{0}>{1}</td>', row_class, result_repr)
|
||||||
if form and not form[cl.model._meta.pk.name].is_hidden:
|
if form and not form[cl.model._meta.pk.name].is_hidden:
|
||||||
yield format_html('<td>{0}</td>', force_unicode(form[cl.model._meta.pk.name]))
|
yield format_html('<td>{0}</td>', force_text(form[cl.model._meta.pk.name]))
|
||||||
|
|
||||||
class ResultList(list):
|
class ResultList(list):
|
||||||
# Wrapper class used to return items in a list_editable
|
# Wrapper class used to return items in a list_editable
|
||||||
|
@ -266,7 +267,7 @@ def result_hidden_fields(cl):
|
||||||
if cl.formset:
|
if cl.formset:
|
||||||
for res, form in zip(cl.result_list, cl.formset.forms):
|
for res, form in zip(cl.result_list, cl.formset.forms):
|
||||||
if form[cl.model._meta.pk.name].is_hidden:
|
if form[cl.model._meta.pk.name].is_hidden:
|
||||||
yield mark_safe(force_unicode(form[cl.model._meta.pk.name]))
|
yield mark_safe(force_text(form[cl.model._meta.pk.name]))
|
||||||
|
|
||||||
@register.inclusion_tag("admin/change_list_results.html")
|
@register.inclusion_tag("admin/change_list_results.html")
|
||||||
def result_list(cl):
|
def result_list(cl):
|
||||||
|
|
|
@ -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_unicode, smart_unicode, smart_str
|
from django.utils.encoding import force_text, smart_text, smart_bytes
|
||||||
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
|
||||||
|
@ -132,7 +132,7 @@ def get_deleted_objects(objs, opts, user, admin_site, using):
|
||||||
# Don't display link to edit, because it either has no
|
# Don't display link to edit, because it either has no
|
||||||
# admin or is edited inline.
|
# admin or is edited inline.
|
||||||
return '%s: %s' % (capfirst(opts.verbose_name),
|
return '%s: %s' % (capfirst(opts.verbose_name),
|
||||||
force_unicode(obj))
|
force_text(obj))
|
||||||
|
|
||||||
to_delete = collector.nested(format_callback)
|
to_delete = collector.nested(format_callback)
|
||||||
|
|
||||||
|
@ -207,8 +207,8 @@ def model_format_dict(obj):
|
||||||
else:
|
else:
|
||||||
opts = obj
|
opts = obj
|
||||||
return {
|
return {
|
||||||
'verbose_name': force_unicode(opts.verbose_name),
|
'verbose_name': force_text(opts.verbose_name),
|
||||||
'verbose_name_plural': force_unicode(opts.verbose_name_plural)
|
'verbose_name_plural': force_text(opts.verbose_name_plural)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -274,10 +274,10 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
|
||||||
label = field.verbose_name
|
label = field.verbose_name
|
||||||
except models.FieldDoesNotExist:
|
except models.FieldDoesNotExist:
|
||||||
if name == "__unicode__":
|
if name == "__unicode__":
|
||||||
label = force_unicode(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_str(model._meta.verbose_name)
|
label = smart_bytes(model._meta.verbose_name)
|
||||||
attr = bytes
|
attr = bytes
|
||||||
else:
|
else:
|
||||||
if callable(name):
|
if callable(name):
|
||||||
|
@ -311,7 +311,7 @@ def help_text_for_field(name, model):
|
||||||
help_text = model._meta.get_field_by_name(name)[0].help_text
|
help_text = model._meta.get_field_by_name(name)[0].help_text
|
||||||
except models.FieldDoesNotExist:
|
except models.FieldDoesNotExist:
|
||||||
help_text = ""
|
help_text = ""
|
||||||
return smart_unicode(help_text)
|
return smart_text(help_text)
|
||||||
|
|
||||||
|
|
||||||
def display_for_field(value, field):
|
def display_for_field(value, field):
|
||||||
|
@ -335,7 +335,7 @@ def display_for_field(value, field):
|
||||||
elif isinstance(field, models.FloatField):
|
elif isinstance(field, models.FloatField):
|
||||||
return formats.number_format(value)
|
return formats.number_format(value)
|
||||||
else:
|
else:
|
||||||
return smart_unicode(value)
|
return smart_text(value)
|
||||||
|
|
||||||
|
|
||||||
def display_for_value(value, boolean=False):
|
def display_for_value(value, boolean=False):
|
||||||
|
@ -353,7 +353,7 @@ def display_for_value(value, boolean=False):
|
||||||
elif isinstance(value, six.integer_types + (decimal.Decimal, float)):
|
elif isinstance(value, six.integer_types + (decimal.Decimal, float)):
|
||||||
return formats.number_format(value)
|
return formats.number_format(value)
|
||||||
else:
|
else:
|
||||||
return smart_unicode(value)
|
return smart_text(value)
|
||||||
|
|
||||||
|
|
||||||
class NotRelationField(Exception):
|
class NotRelationField(Exception):
|
||||||
|
|
|
@ -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_unicode, smart_str
|
from django.utils.encoding import force_text, smart_bytes
|
||||||
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
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ class ChangeList(object):
|
||||||
title = ugettext('Select %s')
|
title = ugettext('Select %s')
|
||||||
else:
|
else:
|
||||||
title = ugettext('Select %s to change')
|
title = ugettext('Select %s to change')
|
||||||
self.title = title % force_unicode(self.opts.verbose_name)
|
self.title = title % force_text(self.opts.verbose_name)
|
||||||
self.pk_attname = self.lookup_opts.pk.attname
|
self.pk_attname = self.lookup_opts.pk.attname
|
||||||
|
|
||||||
def get_filters(self, request):
|
def get_filters(self, request):
|
||||||
|
@ -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_str(key)] = value
|
lookup_params[smart_bytes(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)
|
||||||
|
|
|
@ -14,7 +14,7 @@ from django.utils.html import escape, format_html, format_html_join
|
||||||
from django.utils.text import Truncator
|
from django.utils.text import Truncator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ class AdminRadioFieldRenderer(RadioFieldRenderer):
|
||||||
return format_html('<ul{0}>\n{1}\n</ul>',
|
return format_html('<ul{0}>\n{1}\n</ul>',
|
||||||
flatatt(self.attrs),
|
flatatt(self.attrs),
|
||||||
format_html_join('\n', '<li>{0}</li>',
|
format_html_join('\n', '<li>{0}</li>',
|
||||||
((force_unicode(w),) for w in self)))
|
((force_text(w),) for w in self)))
|
||||||
|
|
||||||
class AdminRadioSelect(forms.RadioSelect):
|
class AdminRadioSelect(forms.RadioSelect):
|
||||||
renderer = AdminRadioFieldRenderer
|
renderer = AdminRadioFieldRenderer
|
||||||
|
@ -197,7 +197,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
|
||||||
# The related object is registered with the same AdminSite
|
# The related object is registered with the same AdminSite
|
||||||
attrs['class'] = 'vManyToManyRawIdAdminField'
|
attrs['class'] = 'vManyToManyRawIdAdminField'
|
||||||
if value:
|
if value:
|
||||||
value = ','.join([force_unicode(v) for v in value])
|
value = ','.join([force_text(v) for v in value])
|
||||||
else:
|
else:
|
||||||
value = ''
|
value = ''
|
||||||
return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
|
return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
|
||||||
|
@ -221,7 +221,7 @@ class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
|
||||||
if len(initial) != len(data):
|
if len(initial) != len(data):
|
||||||
return True
|
return True
|
||||||
for pk1, pk2 in zip(initial, data):
|
for pk1, pk2 in zip(initial, data):
|
||||||
if force_unicode(pk1) != force_unicode(pk2):
|
if force_text(pk1) != force_text(pk2):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -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_str
|
from django.utils.encoding import smart_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_str("<%s>" % thing_being_parsed)
|
thing_being_parsed = smart_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)
|
||||||
|
|
|
@ -14,6 +14,7 @@ from django.core import urlresolvers
|
||||||
from django.contrib.admindocs import utils
|
from django.contrib.admindocs import utils
|
||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ def template_tag_index(request):
|
||||||
load_all_installed_template_libraries()
|
load_all_installed_template_libraries()
|
||||||
|
|
||||||
tags = []
|
tags = []
|
||||||
app_libs = template.libraries.items()
|
app_libs = list(six.iteritems(template.libraries))
|
||||||
builtin_libs = [(None, lib) for lib in template.builtins]
|
builtin_libs = [(None, lib) for lib in template.builtins]
|
||||||
for module_name, library in builtin_libs + app_libs:
|
for module_name, library in builtin_libs + app_libs:
|
||||||
for tag_name, tag_func in library.tags.items():
|
for tag_name, tag_func in library.tags.items():
|
||||||
|
@ -83,7 +84,7 @@ def template_filter_index(request):
|
||||||
load_all_installed_template_libraries()
|
load_all_installed_template_libraries()
|
||||||
|
|
||||||
filters = []
|
filters = []
|
||||||
app_libs = template.libraries.items()
|
app_libs = list(six.iteritems(template.libraries))
|
||||||
builtin_libs = [(None, lib) for lib in template.builtins]
|
builtin_libs = [(None, lib) for lib in template.builtins]
|
||||||
for module_name, library in builtin_libs + app_libs:
|
for module_name, library in builtin_libs + app_libs:
|
||||||
for filter_name, filter_func in library.filters.items():
|
for filter_name, filter_func in library.filters.items():
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.template.response import TemplateResponse
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
from django.views.decorators.csrf import csrf_protect
|
from django.views.decorators.csrf import csrf_protect
|
||||||
from django.views.decorators.debug import sensitive_post_parameters
|
from django.views.decorators.debug import sensitive_post_parameters
|
||||||
|
@ -128,7 +129,7 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
else:
|
else:
|
||||||
form = self.change_password_form(user)
|
form = self.change_password_form(user)
|
||||||
|
|
||||||
fieldsets = [(None, {'fields': form.base_fields.keys()})]
|
fieldsets = [(None, {'fields': list(form.base_fields)})]
|
||||||
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
adminForm = admin.helpers.AdminForm(form, fieldsets, {})
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
|
|
|
@ -11,8 +11,9 @@ class PermLookupDict(object):
|
||||||
def __getitem__(self, perm_name):
|
def __getitem__(self, perm_name):
|
||||||
return self.user.has_perm("%s.%s" % (self.module_name, perm_name))
|
return self.user.has_perm("%s.%s" % (self.module_name, perm_name))
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return self.user.has_module_perms(self.module_name)
|
return self.user.has_module_perms(self.module_name)
|
||||||
|
__nonzero__ = __bool__ # Python 2
|
||||||
|
|
||||||
|
|
||||||
class PermWrapper(object):
|
class PermWrapper(object):
|
||||||
|
|
|
@ -89,9 +89,9 @@ class UserCreationForm(forms.ModelForm):
|
||||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
password1 = self.cleaned_data.get("password1", "")
|
password1 = self.cleaned_data.get("password1")
|
||||||
password2 = self.cleaned_data["password2"]
|
password2 = self.cleaned_data.get("password2")
|
||||||
if password1 != password2:
|
if password1 and password2 and password1 != password2:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
self.error_messages['password_mismatch'])
|
self.error_messages['password_mismatch'])
|
||||||
return password2
|
return password2
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
@ -7,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_str
|
from django.utils.encoding import smart_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)
|
||||||
|
@ -218,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 = hash.encode('base64').strip()
|
hash = base64.b64encode(hash).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):
|
||||||
|
@ -298,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_str(salt + password)).hexdigest()
|
hash = hashlib.sha1(smart_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):
|
||||||
|
@ -326,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_str(salt + password)).hexdigest()
|
hash = hashlib.md5(smart_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):
|
||||||
|
@ -360,7 +361,7 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
return hashlib.md5(smart_str(password)).hexdigest()
|
return hashlib.md5(smart_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.six.moves import input
|
||||||
|
|
||||||
|
|
||||||
def _get_permission_codename(action, opts):
|
def _get_permission_codename(action, opts):
|
||||||
|
@ -66,10 +67,10 @@ def create_superuser(app, created_models, verbosity, db, **kwargs):
|
||||||
msg = ("\nYou just installed Django's auth system, which means you "
|
msg = ("\nYou just installed Django's auth system, which means you "
|
||||||
"don't have any superusers defined.\nWould you like to create one "
|
"don't have any superusers defined.\nWould you like to create one "
|
||||||
"now? (yes/no): ")
|
"now? (yes/no): ")
|
||||||
confirm = raw_input(msg)
|
confirm = input(msg)
|
||||||
while 1:
|
while 1:
|
||||||
if confirm not in ('yes', 'no'):
|
if confirm not in ('yes', 'no'):
|
||||||
confirm = raw_input('Please enter either "yes" or "no": ')
|
confirm = input('Please enter either "yes" or "no": ')
|
||||||
continue
|
continue
|
||||||
if confirm == 'yes':
|
if confirm == 'yes':
|
||||||
call_command("createsuperuser", interactive=True, database=db)
|
call_command("createsuperuser", interactive=True, database=db)
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.contrib.auth.management import get_default_username
|
||||||
from django.core import exceptions
|
from django.core import exceptions
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.db import DEFAULT_DB_ALIAS
|
from django.db import DEFAULT_DB_ALIAS
|
||||||
|
from django.utils.six.moves import input
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
RE_VALID_USERNAME = re.compile('[\w.@+-]+$')
|
RE_VALID_USERNAME = re.compile('[\w.@+-]+$')
|
||||||
|
@ -76,7 +77,7 @@ class Command(BaseCommand):
|
||||||
input_msg = 'Username'
|
input_msg = 'Username'
|
||||||
if default_username:
|
if default_username:
|
||||||
input_msg += ' (leave blank to use %r)' % default_username
|
input_msg += ' (leave blank to use %r)' % default_username
|
||||||
username = raw_input(input_msg + ': ')
|
username = input(input_msg + ': ')
|
||||||
if default_username and username == '':
|
if default_username and username == '':
|
||||||
username = default_username
|
username = default_username
|
||||||
if not RE_VALID_USERNAME.match(username):
|
if not RE_VALID_USERNAME.match(username):
|
||||||
|
@ -94,7 +95,7 @@ class Command(BaseCommand):
|
||||||
# Get an email
|
# Get an email
|
||||||
while 1:
|
while 1:
|
||||||
if not email:
|
if not email:
|
||||||
email = raw_input('E-mail address: ')
|
email = input('E-mail address: ')
|
||||||
try:
|
try:
|
||||||
is_valid_email(email)
|
is_valid_email(email)
|
||||||
except exceptions.ValidationError:
|
except exceptions.ValidationError:
|
||||||
|
|
|
@ -8,7 +8,8 @@ from django.core import mail
|
||||||
from django.forms.fields import Field, EmailField
|
from django.forms.fields import Field, EmailField
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils import six
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ class UserCreationFormTest(TestCase):
|
||||||
form = UserCreationForm(data)
|
form = UserCreationForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["username"].errors,
|
self.assertEqual(form["username"].errors,
|
||||||
[force_unicode(form.error_messages['duplicate_username'])])
|
[force_text(form.error_messages['duplicate_username'])])
|
||||||
|
|
||||||
def test_invalid_data(self):
|
def test_invalid_data(self):
|
||||||
data = {
|
data = {
|
||||||
|
@ -38,7 +39,7 @@ class UserCreationFormTest(TestCase):
|
||||||
form = UserCreationForm(data)
|
form = UserCreationForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["username"].errors,
|
self.assertEqual(form["username"].errors,
|
||||||
[force_unicode(form.fields['username'].error_messages['invalid'])])
|
[force_text(form.fields['username'].error_messages['invalid'])])
|
||||||
|
|
||||||
def test_password_verification(self):
|
def test_password_verification(self):
|
||||||
# The verification password is incorrect.
|
# The verification password is incorrect.
|
||||||
|
@ -50,13 +51,13 @@ class UserCreationFormTest(TestCase):
|
||||||
form = UserCreationForm(data)
|
form = UserCreationForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["password2"].errors,
|
self.assertEqual(form["password2"].errors,
|
||||||
[force_unicode(form.error_messages['password_mismatch'])])
|
[force_text(form.error_messages['password_mismatch'])])
|
||||||
|
|
||||||
def test_both_passwords(self):
|
def test_both_passwords(self):
|
||||||
# One (or both) passwords weren't given
|
# One (or both) passwords weren't given
|
||||||
data = {'username': 'jsmith'}
|
data = {'username': 'jsmith'}
|
||||||
form = UserCreationForm(data)
|
form = UserCreationForm(data)
|
||||||
required_error = [force_unicode(Field.default_error_messages['required'])]
|
required_error = [force_text(Field.default_error_messages['required'])]
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form['password1'].errors, required_error)
|
self.assertEqual(form['password1'].errors, required_error)
|
||||||
self.assertEqual(form['password2'].errors, required_error)
|
self.assertEqual(form['password2'].errors, required_error)
|
||||||
|
@ -65,6 +66,7 @@ class UserCreationFormTest(TestCase):
|
||||||
form = UserCreationForm(data)
|
form = UserCreationForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form['password1'].errors, required_error)
|
self.assertEqual(form['password1'].errors, required_error)
|
||||||
|
self.assertEqual(form['password2'].errors, [])
|
||||||
|
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
# The success case.
|
# The success case.
|
||||||
|
@ -94,7 +96,7 @@ class AuthenticationFormTest(TestCase):
|
||||||
form = AuthenticationForm(None, data)
|
form = AuthenticationForm(None, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form.non_field_errors(),
|
self.assertEqual(form.non_field_errors(),
|
||||||
[force_unicode(form.error_messages['invalid_login'])])
|
[force_text(form.error_messages['invalid_login'])])
|
||||||
|
|
||||||
def test_inactive_user(self):
|
def test_inactive_user(self):
|
||||||
# The user is inactive.
|
# The user is inactive.
|
||||||
|
@ -105,7 +107,7 @@ class AuthenticationFormTest(TestCase):
|
||||||
form = AuthenticationForm(None, data)
|
form = AuthenticationForm(None, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form.non_field_errors(),
|
self.assertEqual(form.non_field_errors(),
|
||||||
[force_unicode(form.error_messages['inactive'])])
|
[force_text(form.error_messages['inactive'])])
|
||||||
|
|
||||||
def test_inactive_user_i18n(self):
|
def test_inactive_user_i18n(self):
|
||||||
with self.settings(USE_I18N=True):
|
with self.settings(USE_I18N=True):
|
||||||
|
@ -118,7 +120,7 @@ class AuthenticationFormTest(TestCase):
|
||||||
form = AuthenticationForm(None, data)
|
form = AuthenticationForm(None, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form.non_field_errors(),
|
self.assertEqual(form.non_field_errors(),
|
||||||
[force_unicode(form.error_messages['inactive'])])
|
[force_text(form.error_messages['inactive'])])
|
||||||
|
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
# The success case
|
# The success case
|
||||||
|
@ -146,7 +148,7 @@ class SetPasswordFormTest(TestCase):
|
||||||
form = SetPasswordForm(user, data)
|
form = SetPasswordForm(user, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["new_password2"].errors,
|
self.assertEqual(form["new_password2"].errors,
|
||||||
[force_unicode(form.error_messages['password_mismatch'])])
|
[force_text(form.error_messages['password_mismatch'])])
|
||||||
|
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
user = User.objects.get(username='testclient')
|
user = User.objects.get(username='testclient')
|
||||||
|
@ -173,7 +175,7 @@ class PasswordChangeFormTest(TestCase):
|
||||||
form = PasswordChangeForm(user, data)
|
form = PasswordChangeForm(user, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["old_password"].errors,
|
self.assertEqual(form["old_password"].errors,
|
||||||
[force_unicode(form.error_messages['password_incorrect'])])
|
[force_text(form.error_messages['password_incorrect'])])
|
||||||
|
|
||||||
def test_password_verification(self):
|
def test_password_verification(self):
|
||||||
# The two new passwords do not match.
|
# The two new passwords do not match.
|
||||||
|
@ -186,7 +188,7 @@ class PasswordChangeFormTest(TestCase):
|
||||||
form = PasswordChangeForm(user, data)
|
form = PasswordChangeForm(user, data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form["new_password2"].errors,
|
self.assertEqual(form["new_password2"].errors,
|
||||||
[force_unicode(form.error_messages['password_mismatch'])])
|
[force_text(form.error_messages['password_mismatch'])])
|
||||||
|
|
||||||
def test_success(self):
|
def test_success(self):
|
||||||
# The success case.
|
# The success case.
|
||||||
|
@ -202,7 +204,7 @@ class PasswordChangeFormTest(TestCase):
|
||||||
def test_field_order(self):
|
def test_field_order(self):
|
||||||
# Regression test - check the order of fields:
|
# Regression test - check the order of fields:
|
||||||
user = User.objects.get(username='testclient')
|
user = User.objects.get(username='testclient')
|
||||||
self.assertEqual(PasswordChangeForm(user, {}).fields.keys(),
|
self.assertEqual(list(PasswordChangeForm(user, {}).fields),
|
||||||
['old_password', 'new_password1', 'new_password2'])
|
['old_password', 'new_password1', 'new_password2'])
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +219,7 @@ class UserChangeFormTest(TestCase):
|
||||||
form = UserChangeForm(data, instance=user)
|
form = UserChangeForm(data, instance=user)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form['username'].errors,
|
self.assertEqual(form['username'].errors,
|
||||||
[force_unicode(form.fields['username'].error_messages['invalid'])])
|
[force_text(form.fields['username'].error_messages['invalid'])])
|
||||||
|
|
||||||
def test_bug_14242(self):
|
def test_bug_14242(self):
|
||||||
# A regression test, introduce by adding an optimization for the
|
# A regression test, introduce by adding an optimization for the
|
||||||
|
@ -272,7 +274,7 @@ class PasswordResetFormTest(TestCase):
|
||||||
form = PasswordResetForm(data)
|
form = PasswordResetForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form['email'].errors,
|
self.assertEqual(form['email'].errors,
|
||||||
[force_unicode(EmailField.default_error_messages['invalid'])])
|
[force_text(EmailField.default_error_messages['invalid'])])
|
||||||
|
|
||||||
def test_nonexistant_email(self):
|
def test_nonexistant_email(self):
|
||||||
# Test nonexistant email address
|
# Test nonexistant email address
|
||||||
|
@ -280,7 +282,7 @@ class PasswordResetFormTest(TestCase):
|
||||||
form = PasswordResetForm(data)
|
form = PasswordResetForm(data)
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
self.assertEqual(form.errors,
|
self.assertEqual(form.errors,
|
||||||
{'email': [force_unicode(form.error_messages['unknown'])]})
|
{'email': [force_text(form.error_messages['unknown'])]})
|
||||||
|
|
||||||
def test_cleaned_data(self):
|
def test_cleaned_data(self):
|
||||||
# Regression test
|
# Regression test
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.auth.models import User
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
@ -46,7 +46,7 @@ class AuthViewsTestCase(TestCase):
|
||||||
self.assertTrue(SESSION_KEY in self.client.session)
|
self.assertTrue(SESSION_KEY in self.client.session)
|
||||||
|
|
||||||
def assertContainsEscaped(self, response, text, **kwargs):
|
def assertContainsEscaped(self, response, text, **kwargs):
|
||||||
return self.assertContains(response, escape(force_unicode(text)), **kwargs)
|
return self.assertContains(response, escape(force_text(text)), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AuthViewNamedURLTests(AuthViewsTestCase):
|
class AuthViewNamedURLTests(AuthViewsTestCase):
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.comments.models import Comment
|
from django.contrib.comments.models import Comment
|
||||||
from django.utils.crypto import salted_hmac, constant_time_compare
|
from django.utils.crypto import salted_hmac, constant_time_compare
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils.text import get_text_list
|
from django.utils.text import get_text_list
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ungettext, ugettext, ugettext_lazy as _
|
from django.utils.translation import ungettext, ugettext, ugettext_lazy as _
|
||||||
|
@ -133,7 +133,7 @@ class CommentDetailsForm(CommentSecurityForm):
|
||||||
"""
|
"""
|
||||||
return dict(
|
return dict(
|
||||||
content_type = ContentType.objects.get_for_model(self.target_object),
|
content_type = ContentType.objects.get_for_model(self.target_object),
|
||||||
object_pk = force_unicode(self.target_object._get_pk_val()),
|
object_pk = force_text(self.target_object._get_pk_val()),
|
||||||
user_name = self.cleaned_data["name"],
|
user_name = self.cleaned_data["name"],
|
||||||
user_email = self.cleaned_data["email"],
|
user_email = self.cleaned_data["email"],
|
||||||
user_url = self.cleaned_data["url"],
|
user_url = self.cleaned_data["url"],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
class CommentManager(models.Manager):
|
class CommentManager(models.Manager):
|
||||||
|
|
||||||
|
@ -18,5 +18,5 @@ class CommentManager(models.Manager):
|
||||||
ct = ContentType.objects.get_for_model(model)
|
ct = ContentType.objects.get_for_model(model)
|
||||||
qs = self.get_query_set().filter(content_type=ct)
|
qs = self.get_query_set().filter(content_type=ct)
|
||||||
if isinstance(model, models.Model):
|
if isinstance(model, models.Model):
|
||||||
qs = qs.filter(object_pk=force_unicode(model._get_pk_val()))
|
qs = qs.filter(object_pk=force_text(model._get_pk_val()))
|
||||||
return qs
|
return qs
|
||||||
|
|
|
@ -3,7 +3,7 @@ from django.template.loader import render_to_string
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib import comments
|
from django.contrib import comments
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ class BaseCommentNode(template.Node):
|
||||||
|
|
||||||
qs = self.comment_model.objects.filter(
|
qs = self.comment_model.objects.filter(
|
||||||
content_type = ctype,
|
content_type = ctype,
|
||||||
object_pk = smart_unicode(object_pk),
|
object_pk = smart_text(object_pk),
|
||||||
site__pk = settings.SITE_ID,
|
site__pk = settings.SITE_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ from django.forms import ModelForm
|
||||||
from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance
|
from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance
|
||||||
from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
|
from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
class GenericForeignKey(object):
|
class GenericForeignKey(object):
|
||||||
"""
|
"""
|
||||||
|
@ -169,7 +169,7 @@ class GenericRelation(RelatedField, Field):
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
def value_to_string(self, obj):
|
||||||
qs = getattr(obj, self.name).all()
|
qs = getattr(obj, self.name).all()
|
||||||
return smart_unicode([instance._get_pk_val() for instance in qs])
|
return smart_text([instance._get_pk_val() for instance in qs])
|
||||||
|
|
||||||
def m2m_db_table(self):
|
def m2m_db_table(self):
|
||||||
return self.rel.to._meta.db_table
|
return self.rel.to._meta.db_table
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import get_apps, get_models, signals
|
from django.db.models import get_apps, get_models, signals
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
from django.utils import six
|
||||||
|
from django.utils.six.moves import input
|
||||||
|
|
||||||
def update_contenttypes(app, created_models, verbosity=2, **kwargs):
|
def update_contenttypes(app, created_models, verbosity=2, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -24,17 +26,17 @@ def update_contenttypes(app, created_models, verbosity=2, **kwargs):
|
||||||
)
|
)
|
||||||
to_remove = [
|
to_remove = [
|
||||||
ct
|
ct
|
||||||
for (model_name, ct) in content_types.iteritems()
|
for (model_name, ct) in six.iteritems(content_types)
|
||||||
if model_name not in app_models
|
if model_name not in app_models
|
||||||
]
|
]
|
||||||
|
|
||||||
cts = ContentType.objects.bulk_create([
|
cts = ContentType.objects.bulk_create([
|
||||||
ContentType(
|
ContentType(
|
||||||
name=smart_unicode(model._meta.verbose_name_raw),
|
name=smart_text(model._meta.verbose_name_raw),
|
||||||
app_label=app_label,
|
app_label=app_label,
|
||||||
model=model_name,
|
model=model_name,
|
||||||
)
|
)
|
||||||
for (model_name, model) in app_models.iteritems()
|
for (model_name, model) in six.iteritems(app_models)
|
||||||
if model_name not in content_types
|
if model_name not in content_types
|
||||||
])
|
])
|
||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
|
@ -48,7 +50,7 @@ def update_contenttypes(app, created_models, verbosity=2, **kwargs):
|
||||||
' %s | %s' % (ct.app_label, ct.model)
|
' %s | %s' % (ct.app_label, ct.model)
|
||||||
for ct in to_remove
|
for ct in to_remove
|
||||||
])
|
])
|
||||||
ok_to_delete = raw_input("""The following content types are stale and need to be deleted:
|
ok_to_delete = input("""The following content types are stale and need to be deleted:
|
||||||
|
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
|
|
@ -1,6 +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 smart_unicode, force_unicode
|
from django.utils.encoding import smart_text, force_text
|
||||||
|
|
||||||
class ContentTypeManager(models.Manager):
|
class ContentTypeManager(models.Manager):
|
||||||
|
|
||||||
|
@ -37,13 +37,13 @@ class ContentTypeManager(models.Manager):
|
||||||
try:
|
try:
|
||||||
ct = self._get_from_cache(opts)
|
ct = self._get_from_cache(opts)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Load or create the ContentType entry. The smart_unicode() is
|
# Load or create the ContentType entry. The smart_text() is
|
||||||
# needed around opts.verbose_name_raw because name_raw might be a
|
# needed around opts.verbose_name_raw because name_raw might be a
|
||||||
# django.utils.functional.__proxy__ object.
|
# django.utils.functional.__proxy__ object.
|
||||||
ct, created = self.get_or_create(
|
ct, created = self.get_or_create(
|
||||||
app_label = opts.app_label,
|
app_label = opts.app_label,
|
||||||
model = opts.object_name.lower(),
|
model = opts.object_name.lower(),
|
||||||
defaults = {'name': smart_unicode(opts.verbose_name_raw)},
|
defaults = {'name': smart_text(opts.verbose_name_raw)},
|
||||||
)
|
)
|
||||||
self._add_to_cache(self.db, ct)
|
self._add_to_cache(self.db, ct)
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ class ContentTypeManager(models.Manager):
|
||||||
ct = self.create(
|
ct = self.create(
|
||||||
app_label=opts.app_label,
|
app_label=opts.app_label,
|
||||||
model=opts.object_name.lower(),
|
model=opts.object_name.lower(),
|
||||||
name=smart_unicode(opts.verbose_name_raw),
|
name=smart_text(opts.verbose_name_raw),
|
||||||
)
|
)
|
||||||
self._add_to_cache(self.db, ct)
|
self._add_to_cache(self.db, ct)
|
||||||
results[ct.model_class()] = ct
|
results[ct.model_class()] = ct
|
||||||
|
@ -147,7 +147,7 @@ class ContentType(models.Model):
|
||||||
if not model or self.name != model._meta.verbose_name_raw:
|
if not model or self.name != model._meta.verbose_name_raw:
|
||||||
return self.name
|
return self.name
|
||||||
else:
|
else:
|
||||||
return force_unicode(model._meta.verbose_name)
|
return force_text(model._meta.verbose_name)
|
||||||
|
|
||||||
def model_class(self):
|
def model_class(self):
|
||||||
"Returns the Python model class for this type of content."
|
"Returns the Python model class for this type of content."
|
||||||
|
|
|
@ -7,7 +7,7 @@ from __future__ import unicode_literals
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
|
from django.utils.encoding import smart_text, smart_bytes, iri_to_uri
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
EMPTY_VALUE = '(None)'
|
EMPTY_VALUE = '(None)'
|
||||||
|
@ -17,12 +17,12 @@ class EasyModel(object):
|
||||||
def __init__(self, site, model):
|
def __init__(self, site, model):
|
||||||
self.site = site
|
self.site = site
|
||||||
self.model = model
|
self.model = model
|
||||||
self.model_list = site.registry.keys()
|
self.model_list = list(site.registry.keys())
|
||||||
self.verbose_name = model._meta.verbose_name
|
self.verbose_name = model._meta.verbose_name
|
||||||
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_str(self.model._meta.object_name)
|
return '<EasyModel for %s>' % smart_bytes(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 +61,7 @@ class EasyField(object):
|
||||||
self.model, self.field = easy_model, field
|
self.model, self.field = easy_model, field
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return smart_bytes('<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,7 +79,7 @@ class EasyChoice(object):
|
||||||
self.value, self.label = value, label
|
self.value, self.label = value, label
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return smart_bytes('<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))
|
||||||
|
@ -89,10 +89,10 @@ class EasyInstance(object):
|
||||||
self.model, self.instance = easy_model, instance
|
self.model, self.instance = easy_model, instance
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
|
return smart_bytes('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
val = smart_unicode(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
|
||||||
|
@ -136,7 +136,7 @@ class EasyInstanceField(object):
|
||||||
self.raw_value = getattr(instance.instance, field.name)
|
self.raw_value = getattr(instance.instance, field.name)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
return smart_bytes('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
"""
|
"""
|
||||||
|
@ -176,8 +176,6 @@ class EasyInstanceField(object):
|
||||||
for plugin_name, plugin in self.model.model_databrowse().plugins.items():
|
for plugin_name, plugin in self.model.model_databrowse().plugins.items():
|
||||||
urls = plugin.urls(plugin_name, self)
|
urls = plugin.urls(plugin_name, self)
|
||||||
if urls is not None:
|
if urls is not None:
|
||||||
#plugin_urls.append(urls)
|
|
||||||
values = self.values()
|
|
||||||
return zip(self.values(), urls)
|
return zip(self.values(), urls)
|
||||||
if self.field.rel:
|
if self.field.rel:
|
||||||
m = EasyModel(self.model.site, self.field.rel.to)
|
m = EasyModel(self.model.site, self.field.rel.to)
|
||||||
|
@ -187,7 +185,7 @@ class EasyInstanceField(object):
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
|
url = '%s%s/%s/objects/%s/' % (self.model.site.root_url, m.model._meta.app_label, m.model._meta.module_name, iri_to_uri(value._get_pk_val()))
|
||||||
lst.append((smart_unicode(value), url))
|
lst.append((smart_text(value), url))
|
||||||
else:
|
else:
|
||||||
lst = [(value, None) for value in self.values()]
|
lst = [(value, None) for value in self.values()]
|
||||||
elif self.field.choices:
|
elif self.field.choices:
|
||||||
|
@ -196,10 +194,10 @@ class EasyInstanceField(object):
|
||||||
url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
|
url = '%s%s/%s/fields/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.name, iri_to_uri(self.raw_value))
|
||||||
lst.append((value, url))
|
lst.append((value, url))
|
||||||
elif isinstance(self.field, models.URLField):
|
elif isinstance(self.field, models.URLField):
|
||||||
val = self.values()[0]
|
val = list(self.values())[0]
|
||||||
lst = [(val, iri_to_uri(val))]
|
lst = [(val, iri_to_uri(val))]
|
||||||
else:
|
else:
|
||||||
lst = [(self.values()[0], None)]
|
lst = [(list(self.values())[0], None)]
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
class EasyQuerySet(QuerySet):
|
class EasyQuerySet(QuerySet):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.databrowse.sites import DatabrowsePlugin
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.utils.html import format_html, format_html_join
|
from django.utils.html import format_html, format_html_join
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.views.generic import dates
|
from django.views.generic import dates
|
||||||
from django.utils import datetime_safe
|
from django.utils import datetime_safe
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class CalendarPlugin(DatabrowsePlugin):
|
||||||
return ''
|
return ''
|
||||||
return format_html('<p class="filter"><strong>View calendar by:</strong> {0}</p>',
|
return format_html('<p class="filter"><strong>View calendar by:</strong> {0}</p>',
|
||||||
format_html_join(', ', '<a href="calendars/{0}/">{1}</a>',
|
format_html_join(', ', '<a href="calendars/{0}/">{1}</a>',
|
||||||
((f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values())))
|
((f.name, force_text(capfirst(f.verbose_name))) for f in fields.values())))
|
||||||
|
|
||||||
def urls(self, plugin_name, easy_instance_field):
|
def urls(self, plugin_name, easy_instance_field):
|
||||||
if isinstance(easy_instance_field.field, models.DateField):
|
if isinstance(easy_instance_field.field, models.DateField):
|
||||||
|
@ -96,7 +96,7 @@ class CalendarPlugin(DatabrowsePlugin):
|
||||||
|
|
||||||
def homepage_view(self, request):
|
def homepage_view(self, request):
|
||||||
easy_model = EasyModel(self.site, self.model)
|
easy_model = EasyModel(self.site, self.model)
|
||||||
field_list = self.fields.values()
|
field_list = list(self.fields.values())
|
||||||
field_list.sort(key=lambda k:k.verbose_name)
|
field_list.sort(key=lambda k:k.verbose_name)
|
||||||
return render_to_response('databrowse/calendar_homepage.html', {
|
return render_to_response('databrowse/calendar_homepage.html', {
|
||||||
'root_url': self.site.root_url,
|
'root_url': self.site.root_url,
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.shortcuts import render_to_response
|
||||||
from django.utils.html import format_html, format_html_join
|
from django.utils.html import format_html, format_html_join
|
||||||
from django.utils.http import urlquote
|
from django.utils.http import urlquote
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
|
||||||
class FieldChoicePlugin(DatabrowsePlugin):
|
class FieldChoicePlugin(DatabrowsePlugin):
|
||||||
|
@ -35,7 +35,7 @@ class FieldChoicePlugin(DatabrowsePlugin):
|
||||||
return ''
|
return ''
|
||||||
return format_html('<p class="filter"><strong>View by:</strong> {0}</p>',
|
return format_html('<p class="filter"><strong>View by:</strong> {0}</p>',
|
||||||
format_html_join(', ', '<a href="fields/{0}/">{1}</a>',
|
format_html_join(', ', '<a href="fields/{0}/">{1}</a>',
|
||||||
((f.name, force_unicode(capfirst(f.verbose_name))) for f in fields.values())))
|
((f.name, force_text(capfirst(f.verbose_name))) for f in fields.values())))
|
||||||
|
|
||||||
def urls(self, plugin_name, easy_instance_field):
|
def urls(self, plugin_name, easy_instance_field):
|
||||||
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
|
if easy_instance_field.field in self.field_dict(easy_instance_field.model.model).values():
|
||||||
|
@ -63,7 +63,7 @@ class FieldChoicePlugin(DatabrowsePlugin):
|
||||||
|
|
||||||
def homepage_view(self, request):
|
def homepage_view(self, request):
|
||||||
easy_model = EasyModel(self.site, self.model)
|
easy_model = EasyModel(self.site, self.model)
|
||||||
field_list = self.fields.values()
|
field_list = list(self.fields.values())
|
||||||
field_list.sort(key=lambda k: k.verbose_name)
|
field_list.sort(key=lambda k: k.verbose_name)
|
||||||
return render_to_response('databrowse/fieldchoice_homepage.html', {'root_url': self.site.root_url, 'model': easy_model, 'field_list': field_list})
|
return render_to_response('databrowse/fieldchoice_homepage.html', {'root_url': self.site.root_url, 'model': easy_model, 'field_list': field_list})
|
||||||
|
|
||||||
|
|
|
@ -317,7 +317,7 @@ class WizardTests(TestCase):
|
||||||
|
|
||||||
class WizardWithProcessStep(TestWizardClass):
|
class WizardWithProcessStep(TestWizardClass):
|
||||||
def process_step(self, request, form, step):
|
def process_step(self, request, form, step):
|
||||||
that.assertTrue(hasattr(form, 'cleaned_data'))
|
that.assertTrue(form.is_valid())
|
||||||
reached[0] = True
|
reached[0] = True
|
||||||
|
|
||||||
wizard = WizardWithProcessStep([WizardPageOneForm,
|
wizard = WizardWithProcessStep([WizardPageOneForm,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
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_str
|
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.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
|
from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
|
||||||
|
|
||||||
|
@ -72,9 +73,9 @@ class BaseStorage(object):
|
||||||
raise NoFileStorageConfigured
|
raise NoFileStorageConfigured
|
||||||
|
|
||||||
files = {}
|
files = {}
|
||||||
for field, field_dict in wizard_files.iteritems():
|
for field, field_dict in six.iteritems(wizard_files):
|
||||||
field_dict = dict((smart_str(k), v)
|
field_dict = dict((smart_bytes(k), v)
|
||||||
for k, v in field_dict.iteritems())
|
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)
|
||||||
|
@ -87,7 +88,7 @@ class BaseStorage(object):
|
||||||
if step not in self.data[self.step_files_key]:
|
if step not in self.data[self.step_files_key]:
|
||||||
self.data[self.step_files_key][step] = {}
|
self.data[self.step_files_key][step] = {}
|
||||||
|
|
||||||
for field, field_file in (files or {}).iteritems():
|
for field, field_file in six.iteritems(files or {}):
|
||||||
tmp_filename = self.file_storage.save(field_file.name, field_file)
|
tmp_filename = self.file_storage.save(field_file.name, field_file)
|
||||||
file_dict = {
|
file_dict = {
|
||||||
'tmp_name': tmp_filename,
|
'tmp_name': tmp_filename,
|
||||||
|
|
|
@ -44,7 +44,7 @@ class StepsHelper(object):
|
||||||
@property
|
@property
|
||||||
def all(self):
|
def all(self):
|
||||||
"Returns the names of all steps/forms."
|
"Returns the names of all steps/forms."
|
||||||
return self._wizard.get_form_list().keys()
|
return list(self._wizard.get_form_list())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def count(self):
|
def count(self):
|
||||||
|
@ -164,14 +164,14 @@ class WizardView(TemplateView):
|
||||||
init_form_list[six.text_type(i)] = form
|
init_form_list[six.text_type(i)] = form
|
||||||
|
|
||||||
# walk through the new created list of forms
|
# walk through the new created list of forms
|
||||||
for form in init_form_list.itervalues():
|
for form in six.itervalues(init_form_list):
|
||||||
if issubclass(form, formsets.BaseFormSet):
|
if issubclass(form, formsets.BaseFormSet):
|
||||||
# if the element is based on BaseFormSet (FormSet/ModelFormSet)
|
# if the element is based on BaseFormSet (FormSet/ModelFormSet)
|
||||||
# we need to override the form variable.
|
# we need to override the form variable.
|
||||||
form = form.form
|
form = form.form
|
||||||
# check if any form contains a FileField, if yes, we need a
|
# check if any form contains a FileField, if yes, we need a
|
||||||
# file_storage added to the wizardview (by subclassing).
|
# file_storage added to the wizardview (by subclassing).
|
||||||
for field in form.base_fields.itervalues():
|
for field in six.itervalues(form.base_fields):
|
||||||
if (isinstance(field, forms.FileField) and
|
if (isinstance(field, forms.FileField) and
|
||||||
not hasattr(cls, 'file_storage')):
|
not hasattr(cls, 'file_storage')):
|
||||||
raise NoFileStorageConfigured
|
raise NoFileStorageConfigured
|
||||||
|
@ -196,7 +196,7 @@ class WizardView(TemplateView):
|
||||||
could use data from other (maybe previous forms).
|
could use data from other (maybe previous forms).
|
||||||
"""
|
"""
|
||||||
form_list = SortedDict()
|
form_list = SortedDict()
|
||||||
for form_key, form_class in self.form_list.iteritems():
|
for form_key, form_class in six.iteritems(self.form_list):
|
||||||
# try to fetch the value from condition list, by default, the form
|
# try to fetch the value from condition list, by default, the form
|
||||||
# gets passed to the new list.
|
# gets passed to the new list.
|
||||||
condition = self.condition_dict.get(form_key, True)
|
condition = self.condition_dict.get(form_key, True)
|
||||||
|
|
|
@ -3,6 +3,8 @@ from django.db.backends.mysql.base import DatabaseOperations
|
||||||
from django.contrib.gis.db.backends.adapter import WKTAdapter
|
from django.contrib.gis.db.backends.adapter import WKTAdapter
|
||||||
from django.contrib.gis.db.backends.base import BaseSpatialOperations
|
from django.contrib.gis.db.backends.base import BaseSpatialOperations
|
||||||
|
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
|
class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
|
|
||||||
compiler_module = 'django.contrib.gis.db.backends.mysql.compiler'
|
compiler_module = 'django.contrib.gis.db.backends.mysql.compiler'
|
||||||
|
@ -30,7 +32,7 @@ class MySQLOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
'within' : 'MBRWithin',
|
'within' : 'MBRWithin',
|
||||||
}
|
}
|
||||||
|
|
||||||
gis_terms = dict([(term, None) for term in geometry_functions.keys() + ['isnull']])
|
gis_terms = dict([(term, None) for term in list(geometry_functions) + ['isnull']])
|
||||||
|
|
||||||
def geo_db_type(self, f):
|
def geo_db_type(self, f):
|
||||||
return f.geom_type
|
return f.geom_type
|
||||||
|
|
|
@ -128,7 +128,7 @@ class OracleOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
geometry_functions.update(distance_functions)
|
geometry_functions.update(distance_functions)
|
||||||
|
|
||||||
gis_terms = ['isnull']
|
gis_terms = ['isnull']
|
||||||
gis_terms += geometry_functions.keys()
|
gis_terms += list(geometry_functions)
|
||||||
gis_terms = dict([(term, None) for term in gis_terms])
|
gis_terms = dict([(term, None) for term in gis_terms])
|
||||||
|
|
||||||
truncate_params = {'relate' : None}
|
truncate_params = {'relate' : None}
|
||||||
|
|
|
@ -163,7 +163,9 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
'contains' : PostGISFunction(prefix, 'Contains'),
|
'contains' : PostGISFunction(prefix, 'Contains'),
|
||||||
'intersects' : PostGISFunction(prefix, 'Intersects'),
|
'intersects' : PostGISFunction(prefix, 'Intersects'),
|
||||||
'relate' : (PostGISRelate, six.string_types),
|
'relate' : (PostGISRelate, six.string_types),
|
||||||
}
|
'coveredby' : PostGISFunction(prefix, 'CoveredBy'),
|
||||||
|
'covers' : PostGISFunction(prefix, 'Covers'),
|
||||||
|
}
|
||||||
|
|
||||||
# Valid distance types and substitutions
|
# Valid distance types and substitutions
|
||||||
dtypes = (Decimal, Distance, float) + six.integer_types
|
dtypes = (Decimal, Distance, float) + six.integer_types
|
||||||
|
@ -178,33 +180,12 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
'distance_gte' : (get_dist_ops('>='), dtypes),
|
'distance_gte' : (get_dist_ops('>='), dtypes),
|
||||||
'distance_lt' : (get_dist_ops('<'), dtypes),
|
'distance_lt' : (get_dist_ops('<'), dtypes),
|
||||||
'distance_lte' : (get_dist_ops('<='), dtypes),
|
'distance_lte' : (get_dist_ops('<='), dtypes),
|
||||||
}
|
'dwithin' : (PostGISFunctionParam(prefix, 'DWithin'), dtypes)
|
||||||
|
}
|
||||||
# Versions 1.2.2+ have KML serialization support.
|
|
||||||
if version < (1, 2, 2):
|
|
||||||
ASKML = False
|
|
||||||
else:
|
|
||||||
ASKML = 'ST_AsKML'
|
|
||||||
self.geometry_functions.update(
|
|
||||||
{'coveredby' : PostGISFunction(prefix, 'CoveredBy'),
|
|
||||||
'covers' : PostGISFunction(prefix, 'Covers'),
|
|
||||||
})
|
|
||||||
self.distance_functions['dwithin'] = (PostGISFunctionParam(prefix, 'DWithin'), dtypes)
|
|
||||||
|
|
||||||
# Adding the distance functions to the geometries lookup.
|
# Adding the distance functions to the geometries lookup.
|
||||||
self.geometry_functions.update(self.distance_functions)
|
self.geometry_functions.update(self.distance_functions)
|
||||||
|
|
||||||
# The union aggregate and topology operation use the same signature
|
|
||||||
# in versions 1.3+.
|
|
||||||
if version < (1, 3, 0):
|
|
||||||
UNIONAGG = 'GeomUnion'
|
|
||||||
UNION = 'Union'
|
|
||||||
MAKELINE = False
|
|
||||||
else:
|
|
||||||
UNIONAGG = 'ST_Union'
|
|
||||||
UNION = 'ST_Union'
|
|
||||||
MAKELINE = 'ST_MakeLine'
|
|
||||||
|
|
||||||
# Only PostGIS versions 1.3.4+ have GeoJSON serialization support.
|
# Only PostGIS versions 1.3.4+ have GeoJSON serialization support.
|
||||||
if version < (1, 3, 4):
|
if version < (1, 3, 4):
|
||||||
GEOJSON = False
|
GEOJSON = False
|
||||||
|
@ -236,8 +217,8 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
|
|
||||||
# Creating a dictionary lookup of all GIS terms for PostGIS.
|
# Creating a dictionary lookup of all GIS terms for PostGIS.
|
||||||
gis_terms = ['isnull']
|
gis_terms = ['isnull']
|
||||||
gis_terms += self.geometry_operators.keys()
|
gis_terms += list(self.geometry_operators)
|
||||||
gis_terms += self.geometry_functions.keys()
|
gis_terms += list(self.geometry_functions)
|
||||||
self.gis_terms = dict([(term, None) for term in gis_terms])
|
self.gis_terms = dict([(term, None) for term in gis_terms])
|
||||||
|
|
||||||
self.area = prefix + 'Area'
|
self.area = prefix + 'Area'
|
||||||
|
@ -256,11 +237,11 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
self.geojson = GEOJSON
|
self.geojson = GEOJSON
|
||||||
self.gml = prefix + 'AsGML'
|
self.gml = prefix + 'AsGML'
|
||||||
self.intersection = prefix + 'Intersection'
|
self.intersection = prefix + 'Intersection'
|
||||||
self.kml = ASKML
|
self.kml = prefix + 'AsKML'
|
||||||
self.length = prefix + 'Length'
|
self.length = prefix + 'Length'
|
||||||
self.length3d = prefix + 'Length3D'
|
self.length3d = prefix + 'Length3D'
|
||||||
self.length_spheroid = prefix + 'length_spheroid'
|
self.length_spheroid = prefix + 'length_spheroid'
|
||||||
self.makeline = MAKELINE
|
self.makeline = prefix + 'MakeLine'
|
||||||
self.mem_size = prefix + 'mem_size'
|
self.mem_size = prefix + 'mem_size'
|
||||||
self.num_geom = prefix + 'NumGeometries'
|
self.num_geom = prefix + 'NumGeometries'
|
||||||
self.num_points =prefix + 'npoints'
|
self.num_points =prefix + 'npoints'
|
||||||
|
@ -275,8 +256,8 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
self.sym_difference = prefix + 'SymDifference'
|
self.sym_difference = prefix + 'SymDifference'
|
||||||
self.transform = prefix + 'Transform'
|
self.transform = prefix + 'Transform'
|
||||||
self.translate = prefix + 'Translate'
|
self.translate = prefix + 'Translate'
|
||||||
self.union = UNION
|
self.union = prefix + 'Union'
|
||||||
self.unionagg = UNIONAGG
|
self.unionagg = prefix + 'Union'
|
||||||
|
|
||||||
def check_aggregate_support(self, aggregate):
|
def check_aggregate_support(self, aggregate):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -99,14 +99,14 @@ class SpatiaLiteCreation(DatabaseCreation):
|
||||||
"""
|
"""
|
||||||
This routine loads up the SpatiaLite SQL file.
|
This routine loads up the SpatiaLite SQL file.
|
||||||
"""
|
"""
|
||||||
if self.connection.ops.spatial_version[:2] >= (3, 0):
|
if self.connection.ops.spatial_version[:2] >= (2, 4):
|
||||||
# Spatialite >= 3.0.x -- No need to load any SQL file, calling
|
# Spatialite >= 2.4 -- No need to load any SQL file, calling
|
||||||
# InitSpatialMetaData() transparently creates the spatial metadata
|
# InitSpatialMetaData() transparently creates the spatial metadata
|
||||||
# tables
|
# tables
|
||||||
cur = self.connection._cursor()
|
cur = self.connection._cursor()
|
||||||
cur.execute("SELECT InitSpatialMetaData()")
|
cur.execute("SELECT InitSpatialMetaData()")
|
||||||
else:
|
else:
|
||||||
# Spatialite < 3.0.x -- Load the initial SQL
|
# Spatialite < 2.4 -- Load the initial SQL
|
||||||
|
|
||||||
# Getting the location of the SpatiaLite SQL file, and confirming
|
# Getting the location of the SpatiaLite SQL file, and confirming
|
||||||
# it exists.
|
# it exists.
|
||||||
|
|
|
@ -131,7 +131,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
|
||||||
|
|
||||||
# Creating the GIS terms dictionary.
|
# Creating the GIS terms dictionary.
|
||||||
gis_terms = ['isnull']
|
gis_terms = ['isnull']
|
||||||
gis_terms += self.geometry_functions.keys()
|
gis_terms += list(self.geometry_functions)
|
||||||
self.gis_terms = dict([(term, None) for term in gis_terms])
|
self.gis_terms = dict([(term, None) for term in gis_terms])
|
||||||
|
|
||||||
if version >= (2, 4, 0):
|
if version >= (2, 4, 0):
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
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
|
||||||
|
@ -25,7 +26,7 @@ class GeoQuerySet(QuerySet):
|
||||||
flat = kwargs.pop('flat', False)
|
flat = kwargs.pop('flat', False)
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise TypeError('Unexpected keyword arguments to values_list: %s'
|
raise TypeError('Unexpected keyword arguments to values_list: %s'
|
||||||
% (kwargs.keys(),))
|
% (list(kwargs),))
|
||||||
if flat and len(fields) > 1:
|
if flat and len(fields) > 1:
|
||||||
raise TypeError("'flat' is not valid when values_list is called with more than one field.")
|
raise TypeError("'flat' is not valid when values_list is called with more than one field.")
|
||||||
return self._clone(klass=GeoValuesListQuerySet, setup=True, flat=flat,
|
return self._clone(klass=GeoValuesListQuerySet, setup=True, flat=flat,
|
||||||
|
@ -531,7 +532,7 @@ class GeoQuerySet(QuerySet):
|
||||||
if settings.get('setup', True):
|
if settings.get('setup', True):
|
||||||
default_args, geo_field = self._spatial_setup(att, desc=settings['desc'], field_name=field_name,
|
default_args, geo_field = self._spatial_setup(att, desc=settings['desc'], field_name=field_name,
|
||||||
geo_field_type=settings.get('geo_field_type', None))
|
geo_field_type=settings.get('geo_field_type', None))
|
||||||
for k, v in default_args.iteritems(): settings['procedure_args'].setdefault(k, v)
|
for k, v in six.iteritems(default_args): settings['procedure_args'].setdefault(k, v)
|
||||||
else:
|
else:
|
||||||
geo_field = settings['geo_field']
|
geo_field = settings['geo_field']
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from django.utils.six.moves import zip
|
||||||
from django.db.backends.util import truncate_name, typecast_timestamp
|
from django.db.backends.util import truncate_name, typecast_timestamp
|
||||||
from django.db.models.sql import compiler
|
from django.db.models.sql import compiler
|
||||||
from django.db.models.sql.constants import MULTI
|
from django.db.models.sql.constants import MULTI
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
SQLCompiler = compiler.SQLCompiler
|
SQLCompiler = compiler.SQLCompiler
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
||||||
qn = self.quote_name_unless_alias
|
qn = self.quote_name_unless_alias
|
||||||
qn2 = self.connection.ops.quote_name
|
qn2 = self.connection.ops.quote_name
|
||||||
result = ['(%s) AS %s' % (self.get_extra_select_format(alias) % col[0], qn2(alias))
|
result = ['(%s) AS %s' % (self.get_extra_select_format(alias) % col[0], qn2(alias))
|
||||||
for alias, col in self.query.extra_select.iteritems()]
|
for alias, col in six.iteritems(self.query.extra_select)]
|
||||||
aliases = set(self.query.extra_select.keys())
|
aliases = set(self.query.extra_select.keys())
|
||||||
if with_aliases:
|
if with_aliases:
|
||||||
col_aliases = aliases.copy()
|
col_aliases = aliases.copy()
|
||||||
|
@ -170,7 +171,7 @@ class GeoSQLCompiler(compiler.SQLCompiler):
|
||||||
objects.
|
objects.
|
||||||
"""
|
"""
|
||||||
values = []
|
values = []
|
||||||
aliases = self.query.extra_select.keys()
|
aliases = list(self.query.extra_select)
|
||||||
|
|
||||||
# Have to set a starting row number offset that is used for
|
# Have to set a starting row number offset that is used for
|
||||||
# determining the correct starting row index -- needed for
|
# determining the correct starting row index -- needed for
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
"""
|
"""
|
||||||
# Python library requisites.
|
# Python library requisites.
|
||||||
import sys
|
import sys
|
||||||
from binascii import a2b_hex
|
from binascii import a2b_hex, b2a_hex
|
||||||
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
|
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
|
||||||
|
|
||||||
# Getting GDAL prerequisites
|
# Getting GDAL prerequisites
|
||||||
|
@ -322,8 +322,7 @@ class OGRGeometry(GDALBase):
|
||||||
@property
|
@property
|
||||||
def hex(self):
|
def hex(self):
|
||||||
"Returns the hexadecimal representation of the WKB (a string)."
|
"Returns the hexadecimal representation of the WKB (a string)."
|
||||||
return str(self.wkb).encode('hex').upper()
|
return b2a_hex(self.wkb).upper()
|
||||||
#return b2a_hex(self.wkb).upper()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
|
|
|
@ -7,6 +7,7 @@ import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.contrib import gis
|
from django.contrib import gis
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
# This global used to store reference geometry data.
|
# This global used to store reference geometry data.
|
||||||
|
@ -25,7 +26,7 @@ def tuplize(seq):
|
||||||
|
|
||||||
def strconvert(d):
|
def strconvert(d):
|
||||||
"Converts all keys in dictionary to str type."
|
"Converts all keys in dictionary to str type."
|
||||||
return dict([(str(k), v) for k, v in d.iteritems()])
|
return dict([(str(k), v) for k, v in six.iteritems(d)])
|
||||||
|
|
||||||
|
|
||||||
def get_ds_file(name, ext):
|
def get_ds_file(name, ext):
|
||||||
|
|
|
@ -143,7 +143,7 @@ class MeasureBase(object):
|
||||||
def __rmul__(self, other):
|
def __rmul__(self, other):
|
||||||
return self * other
|
return self * other
|
||||||
|
|
||||||
def __div__(self, other):
|
def __truediv__(self, other):
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
return self.standard / other.standard
|
return self.standard / other.standard
|
||||||
if isinstance(other, NUMERIC_TYPES):
|
if isinstance(other, NUMERIC_TYPES):
|
||||||
|
@ -151,16 +151,19 @@ class MeasureBase(object):
|
||||||
**{self.STANDARD_UNIT: (self.standard / other)})
|
**{self.STANDARD_UNIT: (self.standard / other)})
|
||||||
else:
|
else:
|
||||||
raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)})
|
raise TypeError('%(class)s must be divided with number or %(class)s' % {"class":pretty_name(self)})
|
||||||
|
__div__ = __truediv__ # Python 2 compatibility
|
||||||
|
|
||||||
def __idiv__(self, other):
|
def __itruediv__(self, other):
|
||||||
if isinstance(other, NUMERIC_TYPES):
|
if isinstance(other, NUMERIC_TYPES):
|
||||||
self.standard /= float(other)
|
self.standard /= float(other)
|
||||||
return self
|
return self
|
||||||
else:
|
else:
|
||||||
raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)})
|
raise TypeError('%(class)s must be divided with number' % {"class":pretty_name(self)})
|
||||||
|
__idiv__ = __itruediv__ # Python 2 compatibility
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return bool(self.standard)
|
return bool(self.standard)
|
||||||
|
__nonzero__ = __bool__ # Python 2 compatibility
|
||||||
|
|
||||||
def default_units(self, kwargs):
|
def default_units(self, kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -169,7 +172,7 @@ class MeasureBase(object):
|
||||||
"""
|
"""
|
||||||
val = 0.0
|
val = 0.0
|
||||||
default_unit = self.STANDARD_UNIT
|
default_unit = self.STANDARD_UNIT
|
||||||
for unit, value in kwargs.iteritems():
|
for unit, value in six.iteritems(kwargs):
|
||||||
if not isinstance(value, float): value = float(value)
|
if not isinstance(value, float): value = float(value)
|
||||||
if unit in self.UNITS:
|
if unit in self.UNITS:
|
||||||
val += self.UNITS[unit] * value
|
val += self.UNITS[unit] * value
|
||||||
|
@ -305,12 +308,13 @@ class Area(MeasureBase):
|
||||||
ALIAS = dict([(k, '%s%s' % (AREA_PREFIX, v)) for k, v in Distance.ALIAS.items()])
|
ALIAS = dict([(k, '%s%s' % (AREA_PREFIX, v)) for k, v in Distance.ALIAS.items()])
|
||||||
LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
|
LALIAS = dict([(k.lower(), v) for k, v in ALIAS.items()])
|
||||||
|
|
||||||
def __div__(self, other):
|
def __truediv__(self, other):
|
||||||
if isinstance(other, NUMERIC_TYPES):
|
if isinstance(other, NUMERIC_TYPES):
|
||||||
return self.__class__(default_unit=self._default_unit,
|
return self.__class__(default_unit=self._default_unit,
|
||||||
**{self.STANDARD_UNIT: (self.standard / other)})
|
**{self.STANDARD_UNIT: (self.standard / other)})
|
||||||
else:
|
else:
|
||||||
raise TypeError('%(class)s must be divided by a number' % {"class":pretty_name(self)})
|
raise TypeError('%(class)s must be divided by a number' % {"class":pretty_name(self)})
|
||||||
|
__div__ = __truediv__ # Python 2 compatibility
|
||||||
|
|
||||||
|
|
||||||
# Shortcuts
|
# Shortcuts
|
||||||
|
|
|
@ -8,7 +8,8 @@ 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_str
|
from django.utils.encoding import smart_bytes
|
||||||
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from django.contrib.gis.shortcuts import render_to_kml, render_to_kmz
|
from django.contrib.gis.shortcuts import render_to_kml, render_to_kmz
|
||||||
|
@ -46,7 +47,7 @@ def sitemap(request, sitemaps, section=None):
|
||||||
raise Http404(_("No sitemap available for section: %r") % section)
|
raise Http404(_("No sitemap available for section: %r") % section)
|
||||||
maps.append(sitemaps[section])
|
maps.append(sitemaps[section])
|
||||||
else:
|
else:
|
||||||
maps = sitemaps.values()
|
maps = list(six.itervalues(sitemaps))
|
||||||
|
|
||||||
page = request.GET.get("p", 1)
|
page = request.GET.get("p", 1)
|
||||||
current_site = get_current_site(request)
|
current_site = get_current_site(request)
|
||||||
|
@ -60,7 +61,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_str(loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls}))
|
xml = smart_bytes(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):
|
||||||
|
|
|
@ -12,7 +12,7 @@ from .models import City, PennsylvaniaCity, State, Truth
|
||||||
|
|
||||||
class GeoRegressionTests(TestCase):
|
class GeoRegressionTests(TestCase):
|
||||||
|
|
||||||
def test01_update(self):
|
def test_update(self):
|
||||||
"Testing GeoQuerySet.update(). See #10411."
|
"Testing GeoQuerySet.update(). See #10411."
|
||||||
pnt = City.objects.get(name='Pueblo').point
|
pnt = City.objects.get(name='Pueblo').point
|
||||||
bak = pnt.clone()
|
bak = pnt.clone()
|
||||||
|
@ -24,7 +24,7 @@ class GeoRegressionTests(TestCase):
|
||||||
City.objects.filter(name='Pueblo').update(point=bak)
|
City.objects.filter(name='Pueblo').update(point=bak)
|
||||||
self.assertEqual(bak, City.objects.get(name='Pueblo').point)
|
self.assertEqual(bak, City.objects.get(name='Pueblo').point)
|
||||||
|
|
||||||
def test02_kmz(self):
|
def test_kmz(self):
|
||||||
"Testing `render_to_kmz` with non-ASCII data. See #11624."
|
"Testing `render_to_kmz` with non-ASCII data. See #11624."
|
||||||
name = '\xc3\x85land Islands'.decode('iso-8859-1')
|
name = '\xc3\x85land Islands'.decode('iso-8859-1')
|
||||||
places = [{'name' : name,
|
places = [{'name' : name,
|
||||||
|
@ -35,7 +35,7 @@ class GeoRegressionTests(TestCase):
|
||||||
|
|
||||||
@no_spatialite
|
@no_spatialite
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test03_extent(self):
|
def test_extent(self):
|
||||||
"Testing `extent` on a table with a single point. See #11827."
|
"Testing `extent` on a table with a single point. See #11827."
|
||||||
pnt = City.objects.get(name='Pueblo').point
|
pnt = City.objects.get(name='Pueblo').point
|
||||||
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
|
ref_ext = (pnt.x, pnt.y, pnt.x, pnt.y)
|
||||||
|
@ -43,14 +43,14 @@ class GeoRegressionTests(TestCase):
|
||||||
for ref_val, val in zip(ref_ext, extent):
|
for ref_val, val in zip(ref_ext, extent):
|
||||||
self.assertAlmostEqual(ref_val, val, 4)
|
self.assertAlmostEqual(ref_val, val, 4)
|
||||||
|
|
||||||
def test04_unicode_date(self):
|
def test_unicode_date(self):
|
||||||
"Testing dates are converted properly, even on SpatiaLite. See #16408."
|
"Testing dates are converted properly, even on SpatiaLite. See #16408."
|
||||||
founded = datetime(1857, 5, 23)
|
founded = datetime(1857, 5, 23)
|
||||||
mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)',
|
mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)',
|
||||||
founded=founded)
|
founded=founded)
|
||||||
self.assertEqual(founded, PennsylvaniaCity.objects.dates('founded', 'day')[0])
|
self.assertEqual(founded, PennsylvaniaCity.objects.dates('founded', 'day')[0])
|
||||||
|
|
||||||
def test05_empty_count(self):
|
def test_empty_count(self):
|
||||||
"Testing that PostGISAdapter.__eq__ does check empty strings. See #13670."
|
"Testing that PostGISAdapter.__eq__ does check empty strings. See #13670."
|
||||||
# contrived example, but need a geo lookup paired with an id__in lookup
|
# contrived example, but need a geo lookup paired with an id__in lookup
|
||||||
pueblo = City.objects.get(name='Pueblo')
|
pueblo = City.objects.get(name='Pueblo')
|
||||||
|
@ -60,12 +60,12 @@ class GeoRegressionTests(TestCase):
|
||||||
# .count() should not throw TypeError in __eq__
|
# .count() should not throw TypeError in __eq__
|
||||||
self.assertEqual(cities_within_state.count(), 1)
|
self.assertEqual(cities_within_state.count(), 1)
|
||||||
|
|
||||||
def test06_defer_or_only_with_annotate(self):
|
def test_defer_or_only_with_annotate(self):
|
||||||
"Regression for #16409. Make sure defer() and only() work with annotate()"
|
"Regression for #16409. Make sure defer() and only() work with annotate()"
|
||||||
self.assertIsInstance(list(City.objects.annotate(Count('point')).defer('name')), list)
|
self.assertIsInstance(list(City.objects.annotate(Count('point')).defer('name')), list)
|
||||||
self.assertIsInstance(list(City.objects.annotate(Count('point')).only('name')), list)
|
self.assertIsInstance(list(City.objects.annotate(Count('point')).only('name')), list)
|
||||||
|
|
||||||
def test07_boolean_conversion(self):
|
def test_boolean_conversion(self):
|
||||||
"Testing Boolean value conversion with the spatial backend, see #15169."
|
"Testing Boolean value conversion with the spatial backend, see #15169."
|
||||||
t1 = Truth.objects.create(val=True)
|
t1 = Truth.objects.create(val=True)
|
||||||
t2 = Truth.objects.create(val=False)
|
t2 = Truth.objects.create(val=False)
|
||||||
|
|
|
@ -15,19 +15,24 @@ from django.utils import six
|
||||||
|
|
||||||
from .models import Country, City, PennsylvaniaCity, State, Track
|
from .models import Country, City, PennsylvaniaCity, State, Track
|
||||||
|
|
||||||
|
from .test_feeds import GeoFeedTest
|
||||||
|
from .test_regress import GeoRegressionTests
|
||||||
|
from .test_sitemaps import GeoSitemapTest
|
||||||
|
|
||||||
|
|
||||||
if not spatialite:
|
if not spatialite:
|
||||||
from .models import Feature, MinusOneSRID
|
from .models import Feature, MinusOneSRID
|
||||||
|
|
||||||
class GeoModelTest(TestCase):
|
class GeoModelTest(TestCase):
|
||||||
|
|
||||||
def test01_fixtures(self):
|
def test_fixtures(self):
|
||||||
"Testing geographic model initialization from fixtures."
|
"Testing geographic model initialization from fixtures."
|
||||||
# Ensuring that data was loaded from initial data fixtures.
|
# Ensuring that data was loaded from initial data fixtures.
|
||||||
self.assertEqual(2, Country.objects.count())
|
self.assertEqual(2, Country.objects.count())
|
||||||
self.assertEqual(8, City.objects.count())
|
self.assertEqual(8, City.objects.count())
|
||||||
self.assertEqual(2, State.objects.count())
|
self.assertEqual(2, State.objects.count())
|
||||||
|
|
||||||
def test02_proxy(self):
|
def test_proxy(self):
|
||||||
"Testing Lazy-Geometry support (using the GeometryProxy)."
|
"Testing Lazy-Geometry support (using the GeometryProxy)."
|
||||||
## Testing on a Point
|
## Testing on a Point
|
||||||
pnt = Point(0, 0)
|
pnt = Point(0, 0)
|
||||||
|
@ -95,165 +100,97 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(ply, State.objects.get(name='NullState').poly)
|
self.assertEqual(ply, State.objects.get(name='NullState').poly)
|
||||||
ns.delete()
|
ns.delete()
|
||||||
|
|
||||||
def test03a_kml(self):
|
@no_mysql
|
||||||
"Testing KML output from the database using GeoQuerySet.kml()."
|
def test_lookup_insert_transform(self):
|
||||||
# Only PostGIS and Spatialite (>=2.4.0-RC4) support KML serialization
|
"Testing automatic transform for lookups and inserts."
|
||||||
if not (postgis or (spatialite and connection.ops.kml)):
|
# San Antonio in 'WGS84' (SRID 4326)
|
||||||
self.assertRaises(NotImplementedError, State.objects.all().kml, field_name='poly')
|
sa_4326 = 'POINT (-98.493183 29.424170)'
|
||||||
return
|
wgs_pnt = fromstr(sa_4326, srid=4326) # Our reference point in WGS84
|
||||||
|
|
||||||
# Should throw a TypeError when trying to obtain KML from a
|
|
||||||
# non-geometry field.
|
|
||||||
qs = City.objects.all()
|
|
||||||
self.assertRaises(TypeError, qs.kml, 'name')
|
|
||||||
|
|
||||||
# The reference KML depends on the version of PostGIS used
|
|
||||||
# (the output stopped including altitude in 1.3.3).
|
|
||||||
if connection.ops.spatial_version >= (1, 3, 3):
|
|
||||||
ref_kml = '<Point><coordinates>-104.609252,38.255001</coordinates></Point>'
|
|
||||||
else:
|
|
||||||
ref_kml = '<Point><coordinates>-104.609252,38.255001,0</coordinates></Point>'
|
|
||||||
|
|
||||||
# Ensuring the KML is as expected.
|
|
||||||
ptown1 = City.objects.kml(field_name='point', precision=9).get(name='Pueblo')
|
|
||||||
ptown2 = City.objects.kml(precision=9).get(name='Pueblo')
|
|
||||||
for ptown in [ptown1, ptown2]:
|
|
||||||
self.assertEqual(ref_kml, ptown.kml)
|
|
||||||
|
|
||||||
def test03b_gml(self):
|
|
||||||
"Testing GML output from the database using GeoQuerySet.gml()."
|
|
||||||
if mysql or (spatialite and not connection.ops.gml) :
|
|
||||||
self.assertRaises(NotImplementedError, Country.objects.all().gml, field_name='mpoly')
|
|
||||||
return
|
|
||||||
|
|
||||||
# Should throw a TypeError when tyring to obtain GML from a
|
|
||||||
# non-geometry field.
|
|
||||||
qs = City.objects.all()
|
|
||||||
self.assertRaises(TypeError, qs.gml, field_name='name')
|
|
||||||
ptown1 = City.objects.gml(field_name='point', precision=9).get(name='Pueblo')
|
|
||||||
ptown2 = City.objects.gml(precision=9).get(name='Pueblo')
|
|
||||||
|
|
||||||
|
# Oracle doesn't have SRID 3084, using 41157.
|
||||||
if oracle:
|
if oracle:
|
||||||
# No precision parameter for Oracle :-/
|
# San Antonio in 'Texas 4205, Southern Zone (1983, meters)' (SRID 41157)
|
||||||
gml_regex = re.compile(r'^<gml:Point srsName="SDO:4326" xmlns:gml="http://www.opengis.net/gml"><gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ </gml:coordinates></gml:Point>')
|
# Used the following Oracle SQL to get this value:
|
||||||
elif spatialite:
|
# SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_CS.TRANSFORM(SDO_GEOMETRY('POINT (-98.493183 29.424170)', 4326), 41157)) FROM DUAL;
|
||||||
# Spatialite has extra colon in SrsName
|
nad_wkt = 'POINT (300662.034646583 5416427.45974934)'
|
||||||
gml_regex = re.compile(r'^<gml:Point SrsName="EPSG::4326"><gml:coordinates decimal="\." cs="," ts=" ">-104.609251\d+,38.255001</gml:coordinates></gml:Point>')
|
nad_srid = 41157
|
||||||
else:
|
else:
|
||||||
gml_regex = re.compile(r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>-104\.60925\d+,38\.255001</gml:coordinates></gml:Point>')
|
# San Antonio in 'NAD83(HARN) / Texas Centric Lambert Conformal' (SRID 3084)
|
||||||
|
nad_wkt = 'POINT (1645978.362408288754523 6276356.025927528738976)' # Used ogr.py in gdal 1.4.1 for this transform
|
||||||
|
nad_srid = 3084
|
||||||
|
|
||||||
for ptown in [ptown1, ptown2]:
|
# Constructing & querying with a point from a different SRID. Oracle
|
||||||
self.assertTrue(gml_regex.match(ptown.gml))
|
# `SDO_OVERLAPBDYINTERSECT` operates differently from
|
||||||
|
# `ST_Intersects`, so contains is used instead.
|
||||||
|
nad_pnt = fromstr(nad_wkt, srid=nad_srid)
|
||||||
def test03c_geojson(self):
|
if oracle:
|
||||||
"Testing GeoJSON output from the database using GeoQuerySet.geojson()."
|
tx = Country.objects.get(mpoly__contains=nad_pnt)
|
||||||
# Only PostGIS 1.3.4+ supports GeoJSON.
|
|
||||||
if not connection.ops.geojson:
|
|
||||||
self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly')
|
|
||||||
return
|
|
||||||
|
|
||||||
if connection.ops.spatial_version >= (1, 4, 0):
|
|
||||||
pueblo_json = '{"type":"Point","coordinates":[-104.609252,38.255001]}'
|
|
||||||
houston_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-95.363151,29.763374]}'
|
|
||||||
victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.305196,48.462611]}'
|
|
||||||
chicago_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
|
|
||||||
else:
|
else:
|
||||||
pueblo_json = '{"type":"Point","coordinates":[-104.60925200,38.25500100]}'
|
tx = Country.objects.get(mpoly__intersects=nad_pnt)
|
||||||
houston_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"coordinates":[-95.36315100,29.76337400]}'
|
self.assertEqual('Texas', tx.name)
|
||||||
victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.30519600,48.46261100]}'
|
|
||||||
chicago_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
|
|
||||||
|
|
||||||
# Precision argument should only be an integer
|
# Creating San Antonio. Remember the Alamo.
|
||||||
self.assertRaises(TypeError, City.objects.geojson, precision='foo')
|
sa = City.objects.create(name='San Antonio', point=nad_pnt)
|
||||||
|
|
||||||
# Reference queries and values.
|
# Now verifying that San Antonio was transformed correctly
|
||||||
# SELECT ST_AsGeoJson("geoapp_city"."point", 8, 0) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Pueblo';
|
sa = City.objects.get(name='San Antonio')
|
||||||
self.assertEqual(pueblo_json, City.objects.geojson().get(name='Pueblo').geojson)
|
self.assertAlmostEqual(wgs_pnt.x, sa.point.x, 6)
|
||||||
|
self.assertAlmostEqual(wgs_pnt.y, sa.point.y, 6)
|
||||||
|
|
||||||
# 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
# If the GeometryField SRID is -1, then we shouldn't perform any
|
||||||
# 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
# transformation if the SRID of the input geometry is different.
|
||||||
# This time we want to include the CRS by using the `crs` keyword.
|
# SpatiaLite does not support missing SRID values.
|
||||||
self.assertEqual(houston_json, City.objects.geojson(crs=True, model_att='json').get(name='Houston').json)
|
if not spatialite:
|
||||||
|
m1 = MinusOneSRID(geom=Point(17, 23, srid=4326))
|
||||||
|
m1.save()
|
||||||
|
self.assertEqual(-1, m1.geom.srid)
|
||||||
|
|
||||||
# 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Victoria';
|
def test_createnull(self):
|
||||||
# 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
"Testing creating a model instance and the geometry being None"
|
||||||
# This time we include the bounding box by using the `bbox` keyword.
|
c = City()
|
||||||
self.assertEqual(victoria_json, City.objects.geojson(bbox=True).get(name='Victoria').geojson)
|
self.assertEqual(c.point, None)
|
||||||
|
|
||||||
# 1.(3|4).x: SELECT ST_AsGeoJson("geoapp_city"."point", 5, 3) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Chicago';
|
@no_spatialite # SpatiaLite does not support abstract geometry columns
|
||||||
# Finally, we set every available keyword.
|
def test_geometryfield(self):
|
||||||
self.assertEqual(chicago_json, City.objects.geojson(bbox=True, crs=True, precision=5).get(name='Chicago').geojson)
|
"Testing the general GeometryField."
|
||||||
|
Feature(name='Point', geom=Point(1, 1)).save()
|
||||||
|
Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))).save()
|
||||||
|
Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))).save()
|
||||||
|
Feature(name='GeometryCollection',
|
||||||
|
geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)),
|
||||||
|
Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))).save()
|
||||||
|
|
||||||
def test03d_svg(self):
|
f_1 = Feature.objects.get(name='Point')
|
||||||
"Testing SVG output using GeoQuerySet.svg()."
|
self.assertEqual(True, isinstance(f_1.geom, Point))
|
||||||
if mysql or oracle:
|
self.assertEqual((1.0, 1.0), f_1.geom.tuple)
|
||||||
self.assertRaises(NotImplementedError, City.objects.svg)
|
f_2 = Feature.objects.get(name='LineString')
|
||||||
return
|
self.assertEqual(True, isinstance(f_2.geom, LineString))
|
||||||
|
self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple)
|
||||||
|
|
||||||
self.assertRaises(TypeError, City.objects.svg, precision='foo')
|
f_3 = Feature.objects.get(name='Polygon')
|
||||||
# SELECT AsSVG(geoapp_city.point, 0, 8) FROM geoapp_city WHERE name = 'Pueblo';
|
self.assertEqual(True, isinstance(f_3.geom, Polygon))
|
||||||
svg1 = 'cx="-104.609252" cy="-38.255001"'
|
f_4 = Feature.objects.get(name='GeometryCollection')
|
||||||
# Even though relative, only one point so it's practically the same except for
|
self.assertEqual(True, isinstance(f_4.geom, GeometryCollection))
|
||||||
# the 'c' letter prefix on the x,y values.
|
self.assertEqual(f_3.geom, f_4.geom[2])
|
||||||
svg2 = svg1.replace('c', '')
|
|
||||||
self.assertEqual(svg1, City.objects.svg().get(name='Pueblo').svg)
|
|
||||||
self.assertEqual(svg2, City.objects.svg(relative=5).get(name='Pueblo').svg)
|
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test04_transform(self):
|
def test_inherited_geofields(self):
|
||||||
"Testing the transform() GeoManager method."
|
"Test GeoQuerySet methods on inherited Geometry fields."
|
||||||
# Pre-transformed points for Houston and Pueblo.
|
# Creating a Pennsylvanian city.
|
||||||
htown = fromstr('POINT(1947516.83115183 6322297.06040572)', srid=3084)
|
mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)')
|
||||||
ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
|
|
||||||
prec = 3 # Precision is low due to version variations in PROJ and GDAL.
|
|
||||||
|
|
||||||
# Asserting the result of the transform operation with the values in
|
# All transformation SQL will need to be performed on the
|
||||||
# the pre-transformed points. Oracle does not have the 3084 SRID.
|
# _parent_ table.
|
||||||
if not oracle:
|
qs = PennsylvaniaCity.objects.transform(32128)
|
||||||
h = City.objects.transform(htown.srid).get(name='Houston')
|
|
||||||
self.assertEqual(3084, h.point.srid)
|
|
||||||
self.assertAlmostEqual(htown.x, h.point.x, prec)
|
|
||||||
self.assertAlmostEqual(htown.y, h.point.y, prec)
|
|
||||||
|
|
||||||
p1 = City.objects.transform(ptown.srid, field_name='point').get(name='Pueblo')
|
self.assertEqual(1, qs.count())
|
||||||
p2 = City.objects.transform(srid=ptown.srid).get(name='Pueblo')
|
for pc in qs: self.assertEqual(32128, pc.point.srid)
|
||||||
for p in [p1, p2]:
|
|
||||||
self.assertEqual(2774, p.point.srid)
|
|
||||||
self.assertAlmostEqual(ptown.x, p.point.x, prec)
|
class GeoLookupTest(TestCase):
|
||||||
self.assertAlmostEqual(ptown.y, p.point.y, prec)
|
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
@no_spatialite # SpatiaLite does not have an Extent function
|
def test_disjoint_lookup(self):
|
||||||
def test05_extent(self):
|
|
||||||
"Testing the `extent` GeoQuerySet method."
|
|
||||||
# Reference query:
|
|
||||||
# `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');`
|
|
||||||
# => BOX(-96.8016128540039 29.7633724212646,-95.3631439208984 32.7820587158203)
|
|
||||||
expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
|
|
||||||
|
|
||||||
qs = City.objects.filter(name__in=('Houston', 'Dallas'))
|
|
||||||
extent = qs.extent()
|
|
||||||
|
|
||||||
for val, exp in zip(extent, expected):
|
|
||||||
self.assertAlmostEqual(exp, val, 4)
|
|
||||||
|
|
||||||
# Only PostGIS has support for the MakeLine aggregate.
|
|
||||||
@no_mysql
|
|
||||||
@no_oracle
|
|
||||||
@no_spatialite
|
|
||||||
def test06_make_line(self):
|
|
||||||
"Testing the `make_line` GeoQuerySet method."
|
|
||||||
# Ensuring that a `TypeError` is raised on models without PointFields.
|
|
||||||
self.assertRaises(TypeError, State.objects.make_line)
|
|
||||||
self.assertRaises(TypeError, Country.objects.make_line)
|
|
||||||
# Reference query:
|
|
||||||
# SELECT AsText(ST_MakeLine(geoapp_city.point)) FROM geoapp_city;
|
|
||||||
ref_line = GEOSGeometry('LINESTRING(-95.363151 29.763374,-96.801611 32.782057,-97.521157 34.464642,174.783117 -41.315268,-104.609252 38.255001,-95.23506 38.971823,-87.650175 41.850385,-123.305196 48.462611)', srid=4326)
|
|
||||||
self.assertEqual(ref_line, City.objects.make_line())
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test09_disjoint(self):
|
|
||||||
"Testing the `disjoint` lookup type."
|
"Testing the `disjoint` lookup type."
|
||||||
ptown = City.objects.get(name='Pueblo')
|
ptown = City.objects.get(name='Pueblo')
|
||||||
qs1 = City.objects.filter(point__disjoint=ptown.point)
|
qs1 = City.objects.filter(point__disjoint=ptown.point)
|
||||||
|
@ -263,7 +200,7 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(1, qs2.count())
|
self.assertEqual(1, qs2.count())
|
||||||
self.assertEqual('Kansas', qs2[0].name)
|
self.assertEqual('Kansas', qs2[0].name)
|
||||||
|
|
||||||
def test10_contains_contained(self):
|
def test_contains_contained_lookups(self):
|
||||||
"Testing the 'contained', 'contains', and 'bbcontains' lookup types."
|
"Testing the 'contained', 'contains', and 'bbcontains' lookup types."
|
||||||
# Getting Texas, yes we were a country -- once ;)
|
# Getting Texas, yes we were a country -- once ;)
|
||||||
texas = Country.objects.get(name='Texas')
|
texas = Country.objects.get(name='Texas')
|
||||||
|
@ -308,86 +245,11 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(1, len(qs))
|
self.assertEqual(1, len(qs))
|
||||||
self.assertEqual('Texas', qs[0].name)
|
self.assertEqual('Texas', qs[0].name)
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test11_lookup_insert_transform(self):
|
|
||||||
"Testing automatic transform for lookups and inserts."
|
|
||||||
# San Antonio in 'WGS84' (SRID 4326)
|
|
||||||
sa_4326 = 'POINT (-98.493183 29.424170)'
|
|
||||||
wgs_pnt = fromstr(sa_4326, srid=4326) # Our reference point in WGS84
|
|
||||||
|
|
||||||
# Oracle doesn't have SRID 3084, using 41157.
|
|
||||||
if oracle:
|
|
||||||
# San Antonio in 'Texas 4205, Southern Zone (1983, meters)' (SRID 41157)
|
|
||||||
# Used the following Oracle SQL to get this value:
|
|
||||||
# SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_CS.TRANSFORM(SDO_GEOMETRY('POINT (-98.493183 29.424170)', 4326), 41157)) FROM DUAL;
|
|
||||||
nad_wkt = 'POINT (300662.034646583 5416427.45974934)'
|
|
||||||
nad_srid = 41157
|
|
||||||
else:
|
|
||||||
# San Antonio in 'NAD83(HARN) / Texas Centric Lambert Conformal' (SRID 3084)
|
|
||||||
nad_wkt = 'POINT (1645978.362408288754523 6276356.025927528738976)' # Used ogr.py in gdal 1.4.1 for this transform
|
|
||||||
nad_srid = 3084
|
|
||||||
|
|
||||||
# Constructing & querying with a point from a different SRID. Oracle
|
|
||||||
# `SDO_OVERLAPBDYINTERSECT` operates differently from
|
|
||||||
# `ST_Intersects`, so contains is used instead.
|
|
||||||
nad_pnt = fromstr(nad_wkt, srid=nad_srid)
|
|
||||||
if oracle:
|
|
||||||
tx = Country.objects.get(mpoly__contains=nad_pnt)
|
|
||||||
else:
|
|
||||||
tx = Country.objects.get(mpoly__intersects=nad_pnt)
|
|
||||||
self.assertEqual('Texas', tx.name)
|
|
||||||
|
|
||||||
# Creating San Antonio. Remember the Alamo.
|
|
||||||
sa = City.objects.create(name='San Antonio', point=nad_pnt)
|
|
||||||
|
|
||||||
# Now verifying that San Antonio was transformed correctly
|
|
||||||
sa = City.objects.get(name='San Antonio')
|
|
||||||
self.assertAlmostEqual(wgs_pnt.x, sa.point.x, 6)
|
|
||||||
self.assertAlmostEqual(wgs_pnt.y, sa.point.y, 6)
|
|
||||||
|
|
||||||
# If the GeometryField SRID is -1, then we shouldn't perform any
|
|
||||||
# transformation if the SRID of the input geometry is different.
|
|
||||||
# SpatiaLite does not support missing SRID values.
|
|
||||||
if not spatialite:
|
|
||||||
m1 = MinusOneSRID(geom=Point(17, 23, srid=4326))
|
|
||||||
m1.save()
|
|
||||||
self.assertEqual(-1, m1.geom.srid)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test12_null_geometries(self):
|
|
||||||
"Testing NULL geometry support, and the `isnull` lookup type."
|
|
||||||
# Creating a state with a NULL boundary.
|
|
||||||
State.objects.create(name='Puerto Rico')
|
|
||||||
|
|
||||||
# Querying for both NULL and Non-NULL values.
|
|
||||||
nullqs = State.objects.filter(poly__isnull=True)
|
|
||||||
validqs = State.objects.filter(poly__isnull=False)
|
|
||||||
|
|
||||||
# Puerto Rico should be NULL (it's a commonwealth unincorporated territory)
|
|
||||||
self.assertEqual(1, len(nullqs))
|
|
||||||
self.assertEqual('Puerto Rico', nullqs[0].name)
|
|
||||||
|
|
||||||
# The valid states should be Colorado & Kansas
|
|
||||||
self.assertEqual(2, len(validqs))
|
|
||||||
state_names = [s.name for s in validqs]
|
|
||||||
self.assertEqual(True, 'Colorado' in state_names)
|
|
||||||
self.assertEqual(True, 'Kansas' in state_names)
|
|
||||||
|
|
||||||
# Saving another commonwealth w/a NULL geometry.
|
|
||||||
nmi = State.objects.create(name='Northern Mariana Islands', poly=None)
|
|
||||||
self.assertEqual(nmi.poly, None)
|
|
||||||
|
|
||||||
# Assigning a geomery and saving -- then UPDATE back to NULL.
|
|
||||||
nmi.poly = 'POLYGON((0 0,1 0,1 1,1 0,0 0))'
|
|
||||||
nmi.save()
|
|
||||||
State.objects.filter(name='Northern Mariana Islands').update(poly=None)
|
|
||||||
self.assertEqual(None, State.objects.get(name='Northern Mariana Islands').poly)
|
|
||||||
|
|
||||||
# Only PostGIS has `left` and `right` lookup types.
|
# Only PostGIS has `left` and `right` lookup types.
|
||||||
@no_mysql
|
@no_mysql
|
||||||
@no_oracle
|
@no_oracle
|
||||||
@no_spatialite
|
@no_spatialite
|
||||||
def test13_left_right(self):
|
def test_left_right_lookups(self):
|
||||||
"Testing the 'left' and 'right' lookup types."
|
"Testing the 'left' and 'right' lookup types."
|
||||||
# Left: A << B => true if xmax(A) < xmin(B)
|
# Left: A << B => true if xmax(A) < xmin(B)
|
||||||
# Right: A >> B => true if xmin(A) > xmax(B)
|
# Right: A >> B => true if xmin(A) > xmax(B)
|
||||||
|
@ -423,7 +285,7 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(2, len(qs))
|
self.assertEqual(2, len(qs))
|
||||||
for c in qs: self.assertEqual(True, c.name in cities)
|
for c in qs: self.assertEqual(True, c.name in cities)
|
||||||
|
|
||||||
def test14_equals(self):
|
def test_equals_lookups(self):
|
||||||
"Testing the 'same_as' and 'equals' lookup types."
|
"Testing the 'same_as' and 'equals' lookup types."
|
||||||
pnt = fromstr('POINT (-95.363151 29.763374)', srid=4326)
|
pnt = fromstr('POINT (-95.363151 29.763374)', srid=4326)
|
||||||
c1 = City.objects.get(point=pnt)
|
c1 = City.objects.get(point=pnt)
|
||||||
|
@ -432,7 +294,37 @@ class GeoModelTest(TestCase):
|
||||||
for c in [c1, c2, c3]: self.assertEqual('Houston', c.name)
|
for c in [c1, c2, c3]: self.assertEqual('Houston', c.name)
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test15_relate(self):
|
def test_null_geometries(self):
|
||||||
|
"Testing NULL geometry support, and the `isnull` lookup type."
|
||||||
|
# Creating a state with a NULL boundary.
|
||||||
|
State.objects.create(name='Puerto Rico')
|
||||||
|
|
||||||
|
# Querying for both NULL and Non-NULL values.
|
||||||
|
nullqs = State.objects.filter(poly__isnull=True)
|
||||||
|
validqs = State.objects.filter(poly__isnull=False)
|
||||||
|
|
||||||
|
# Puerto Rico should be NULL (it's a commonwealth unincorporated territory)
|
||||||
|
self.assertEqual(1, len(nullqs))
|
||||||
|
self.assertEqual('Puerto Rico', nullqs[0].name)
|
||||||
|
|
||||||
|
# The valid states should be Colorado & Kansas
|
||||||
|
self.assertEqual(2, len(validqs))
|
||||||
|
state_names = [s.name for s in validqs]
|
||||||
|
self.assertEqual(True, 'Colorado' in state_names)
|
||||||
|
self.assertEqual(True, 'Kansas' in state_names)
|
||||||
|
|
||||||
|
# Saving another commonwealth w/a NULL geometry.
|
||||||
|
nmi = State.objects.create(name='Northern Mariana Islands', poly=None)
|
||||||
|
self.assertEqual(nmi.poly, None)
|
||||||
|
|
||||||
|
# Assigning a geomery and saving -- then UPDATE back to NULL.
|
||||||
|
nmi.poly = 'POLYGON((0 0,1 0,1 1,1 0,0 0))'
|
||||||
|
nmi.save()
|
||||||
|
State.objects.filter(name='Northern Mariana Islands').update(poly=None)
|
||||||
|
self.assertEqual(None, State.objects.get(name='Northern Mariana Islands').poly)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
def test_relate_lookup(self):
|
||||||
"Testing the 'relate' lookup type."
|
"Testing the 'relate' lookup type."
|
||||||
# To make things more interesting, we will have our Texas reference point in
|
# To make things more interesting, we will have our Texas reference point in
|
||||||
# different SRIDs.
|
# different SRIDs.
|
||||||
|
@ -474,60 +366,12 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual('Texas', Country.objects.get(mpoly__relate=(pnt2, intersects_mask)).name)
|
self.assertEqual('Texas', Country.objects.get(mpoly__relate=(pnt2, intersects_mask)).name)
|
||||||
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
|
self.assertEqual('Lawrence', City.objects.get(point__relate=(ks.poly, intersects_mask)).name)
|
||||||
|
|
||||||
def test16_createnull(self):
|
|
||||||
"Testing creating a model instance and the geometry being None"
|
class GeoQuerySetTest(TestCase):
|
||||||
c = City()
|
# Please keep the tests in GeoQuerySet method's alphabetic order
|
||||||
self.assertEqual(c.point, None)
|
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test17_unionagg(self):
|
def test_centroid(self):
|
||||||
"Testing the `unionagg` (aggregate union) GeoManager method."
|
|
||||||
tx = Country.objects.get(name='Texas').mpoly
|
|
||||||
# Houston, Dallas -- Oracle has different order.
|
|
||||||
union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
|
|
||||||
union2 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
|
|
||||||
qs = City.objects.filter(point__within=tx)
|
|
||||||
self.assertRaises(TypeError, qs.unionagg, 'name')
|
|
||||||
# Using `field_name` keyword argument in one query and specifying an
|
|
||||||
# order in the other (which should not be used because this is
|
|
||||||
# an aggregate method on a spatial column)
|
|
||||||
u1 = qs.unionagg(field_name='point')
|
|
||||||
u2 = qs.order_by('name').unionagg()
|
|
||||||
tol = 0.00001
|
|
||||||
if oracle:
|
|
||||||
union = union2
|
|
||||||
else:
|
|
||||||
union = union1
|
|
||||||
self.assertEqual(True, union.equals_exact(u1, tol))
|
|
||||||
self.assertEqual(True, union.equals_exact(u2, tol))
|
|
||||||
qs = City.objects.filter(name='NotACity')
|
|
||||||
self.assertEqual(None, qs.unionagg(field_name='point'))
|
|
||||||
|
|
||||||
@no_spatialite # SpatiaLite does not support abstract geometry columns
|
|
||||||
def test18_geometryfield(self):
|
|
||||||
"Testing the general GeometryField."
|
|
||||||
Feature(name='Point', geom=Point(1, 1)).save()
|
|
||||||
Feature(name='LineString', geom=LineString((0, 0), (1, 1), (5, 5))).save()
|
|
||||||
Feature(name='Polygon', geom=Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)))).save()
|
|
||||||
Feature(name='GeometryCollection',
|
|
||||||
geom=GeometryCollection(Point(2, 2), LineString((0, 0), (2, 2)),
|
|
||||||
Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))))).save()
|
|
||||||
|
|
||||||
f_1 = Feature.objects.get(name='Point')
|
|
||||||
self.assertEqual(True, isinstance(f_1.geom, Point))
|
|
||||||
self.assertEqual((1.0, 1.0), f_1.geom.tuple)
|
|
||||||
f_2 = Feature.objects.get(name='LineString')
|
|
||||||
self.assertEqual(True, isinstance(f_2.geom, LineString))
|
|
||||||
self.assertEqual(((0.0, 0.0), (1.0, 1.0), (5.0, 5.0)), f_2.geom.tuple)
|
|
||||||
|
|
||||||
f_3 = Feature.objects.get(name='Polygon')
|
|
||||||
self.assertEqual(True, isinstance(f_3.geom, Polygon))
|
|
||||||
f_4 = Feature.objects.get(name='GeometryCollection')
|
|
||||||
self.assertEqual(True, isinstance(f_4.geom, GeometryCollection))
|
|
||||||
self.assertEqual(f_3.geom, f_4.geom[2])
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test19_centroid(self):
|
|
||||||
"Testing the `centroid` GeoQuerySet method."
|
"Testing the `centroid` GeoQuerySet method."
|
||||||
qs = State.objects.exclude(poly__isnull=True).centroid()
|
qs = State.objects.exclude(poly__isnull=True).centroid()
|
||||||
if oracle:
|
if oracle:
|
||||||
|
@ -540,84 +384,7 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(True, s.poly.centroid.equals_exact(s.centroid, tol))
|
self.assertEqual(True, s.poly.centroid.equals_exact(s.centroid, tol))
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test20_pointonsurface(self):
|
def test_diff_intersection_union(self):
|
||||||
"Testing the `point_on_surface` GeoQuerySet method."
|
|
||||||
# Reference values.
|
|
||||||
if oracle:
|
|
||||||
# SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_GEOM.SDO_POINTONSURFACE(GEOAPP_COUNTRY.MPOLY, 0.05)) FROM GEOAPP_COUNTRY;
|
|
||||||
ref = {'New Zealand' : fromstr('POINT (174.616364 -36.100861)', srid=4326),
|
|
||||||
'Texas' : fromstr('POINT (-103.002434 36.500397)', srid=4326),
|
|
||||||
}
|
|
||||||
|
|
||||||
elif postgis or spatialite:
|
|
||||||
# Using GEOSGeometry to compute the reference point on surface values
|
|
||||||
# -- since PostGIS also uses GEOS these should be the same.
|
|
||||||
ref = {'New Zealand' : Country.objects.get(name='New Zealand').mpoly.point_on_surface,
|
|
||||||
'Texas' : Country.objects.get(name='Texas').mpoly.point_on_surface
|
|
||||||
}
|
|
||||||
|
|
||||||
for c in Country.objects.point_on_surface():
|
|
||||||
if spatialite:
|
|
||||||
# XXX This seems to be a WKT-translation-related precision issue?
|
|
||||||
tol = 0.00001
|
|
||||||
else:
|
|
||||||
tol = 0.000000001
|
|
||||||
self.assertEqual(True, ref[c.name].equals_exact(c.point_on_surface, tol))
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
@no_oracle
|
|
||||||
def test21_scale(self):
|
|
||||||
"Testing the `scale` GeoQuerySet method."
|
|
||||||
xfac, yfac = 2, 3
|
|
||||||
tol = 5 # XXX The low precision tolerance is for SpatiaLite
|
|
||||||
qs = Country.objects.scale(xfac, yfac, model_att='scaled')
|
|
||||||
for c in qs:
|
|
||||||
for p1, p2 in zip(c.mpoly, c.scaled):
|
|
||||||
for r1, r2 in zip(p1, p2):
|
|
||||||
for c1, c2 in zip(r1.coords, r2.coords):
|
|
||||||
self.assertAlmostEqual(c1[0] * xfac, c2[0], tol)
|
|
||||||
self.assertAlmostEqual(c1[1] * yfac, c2[1], tol)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
@no_oracle
|
|
||||||
def test22_translate(self):
|
|
||||||
"Testing the `translate` GeoQuerySet method."
|
|
||||||
xfac, yfac = 5, -23
|
|
||||||
qs = Country.objects.translate(xfac, yfac, model_att='translated')
|
|
||||||
for c in qs:
|
|
||||||
for p1, p2 in zip(c.mpoly, c.translated):
|
|
||||||
for r1, r2 in zip(p1, p2):
|
|
||||||
for c1, c2 in zip(r1.coords, r2.coords):
|
|
||||||
# XXX The low precision is for SpatiaLite
|
|
||||||
self.assertAlmostEqual(c1[0] + xfac, c2[0], 5)
|
|
||||||
self.assertAlmostEqual(c1[1] + yfac, c2[1], 5)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test23_numgeom(self):
|
|
||||||
"Testing the `num_geom` GeoQuerySet method."
|
|
||||||
# Both 'countries' only have two geometries.
|
|
||||||
for c in Country.objects.num_geom(): self.assertEqual(2, c.num_geom)
|
|
||||||
for c in City.objects.filter(point__isnull=False).num_geom():
|
|
||||||
# Oracle will return 1 for the number of geometries on non-collections,
|
|
||||||
# whereas PostGIS will return None.
|
|
||||||
if postgis:
|
|
||||||
self.assertEqual(None, c.num_geom)
|
|
||||||
else:
|
|
||||||
self.assertEqual(1, c.num_geom)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
@no_spatialite # SpatiaLite can only count vertices in LineStrings
|
|
||||||
def test24_numpoints(self):
|
|
||||||
"Testing the `num_points` GeoQuerySet method."
|
|
||||||
for c in Country.objects.num_points():
|
|
||||||
self.assertEqual(c.mpoly.num_points, c.num_points)
|
|
||||||
|
|
||||||
if not oracle:
|
|
||||||
# Oracle cannot count vertices in Point geometries.
|
|
||||||
for c in City.objects.num_points(): self.assertEqual(1, c.num_points)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
def test25_geoset(self):
|
|
||||||
"Testing the `difference`, `intersection`, `sym_difference`, and `union` GeoQuerySet methods."
|
"Testing the `difference`, `intersection`, `sym_difference`, and `union` GeoQuerySet methods."
|
||||||
geom = Point(5, 23)
|
geom = Point(5, 23)
|
||||||
tol = 1
|
tol = 1
|
||||||
|
@ -644,22 +411,232 @@ class GeoModelTest(TestCase):
|
||||||
self.assertEqual(c.mpoly.union(geom), c.union)
|
self.assertEqual(c.mpoly.union(geom), c.union)
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
def test26_inherited_geofields(self):
|
@no_spatialite # SpatiaLite does not have an Extent function
|
||||||
"Test GeoQuerySet methods on inherited Geometry fields."
|
def test_extent(self):
|
||||||
# Creating a Pennsylvanian city.
|
"Testing the `extent` GeoQuerySet method."
|
||||||
mansfield = PennsylvaniaCity.objects.create(name='Mansfield', county='Tioga', point='POINT(-77.071445 41.823881)')
|
# Reference query:
|
||||||
|
# `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');`
|
||||||
|
# => BOX(-96.8016128540039 29.7633724212646,-95.3631439208984 32.7820587158203)
|
||||||
|
expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
|
||||||
|
|
||||||
# All transformation SQL will need to be performed on the
|
qs = City.objects.filter(name__in=('Houston', 'Dallas'))
|
||||||
# _parent_ table.
|
extent = qs.extent()
|
||||||
qs = PennsylvaniaCity.objects.transform(32128)
|
|
||||||
|
|
||||||
self.assertEqual(1, qs.count())
|
for val, exp in zip(extent, expected):
|
||||||
for pc in qs: self.assertEqual(32128, pc.point.srid)
|
self.assertAlmostEqual(exp, val, 4)
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
@no_oracle
|
@no_oracle
|
||||||
@no_spatialite
|
@no_spatialite
|
||||||
def test27_snap_to_grid(self):
|
def test_force_rhr(self):
|
||||||
|
"Testing GeoQuerySet.force_rhr()."
|
||||||
|
rings = ( ( (0, 0), (5, 0), (0, 5), (0, 0) ),
|
||||||
|
( (1, 1), (1, 3), (3, 1), (1, 1) ),
|
||||||
|
)
|
||||||
|
rhr_rings = ( ( (0, 0), (0, 5), (5, 0), (0, 0) ),
|
||||||
|
( (1, 1), (3, 1), (1, 3), (1, 1) ),
|
||||||
|
)
|
||||||
|
State.objects.create(name='Foo', poly=Polygon(*rings))
|
||||||
|
s = State.objects.force_rhr().get(name='Foo')
|
||||||
|
self.assertEqual(rhr_rings, s.force_rhr.coords)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_oracle
|
||||||
|
@no_spatialite
|
||||||
|
def test_geohash(self):
|
||||||
|
"Testing GeoQuerySet.geohash()."
|
||||||
|
if not connection.ops.geohash: return
|
||||||
|
# Reference query:
|
||||||
|
# SELECT ST_GeoHash(point) FROM geoapp_city WHERE name='Houston';
|
||||||
|
# SELECT ST_GeoHash(point, 5) FROM geoapp_city WHERE name='Houston';
|
||||||
|
ref_hash = '9vk1mfq8jx0c8e0386z6'
|
||||||
|
h1 = City.objects.geohash().get(name='Houston')
|
||||||
|
h2 = City.objects.geohash(precision=5).get(name='Houston')
|
||||||
|
self.assertEqual(ref_hash, h1.geohash)
|
||||||
|
self.assertEqual(ref_hash[:5], h2.geohash)
|
||||||
|
|
||||||
|
def test_geojson(self):
|
||||||
|
"Testing GeoJSON output from the database using GeoQuerySet.geojson()."
|
||||||
|
# Only PostGIS 1.3.4+ supports GeoJSON.
|
||||||
|
if not connection.ops.geojson:
|
||||||
|
self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly')
|
||||||
|
return
|
||||||
|
|
||||||
|
if connection.ops.spatial_version >= (1, 4, 0):
|
||||||
|
pueblo_json = '{"type":"Point","coordinates":[-104.609252,38.255001]}'
|
||||||
|
houston_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-95.363151,29.763374]}'
|
||||||
|
victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.305196,48.462611]}'
|
||||||
|
chicago_json = '{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
|
||||||
|
else:
|
||||||
|
pueblo_json = '{"type":"Point","coordinates":[-104.60925200,38.25500100]}'
|
||||||
|
houston_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"coordinates":[-95.36315100,29.76337400]}'
|
||||||
|
victoria_json = '{"type":"Point","bbox":[-123.30519600,48.46261100,-123.30519600,48.46261100],"coordinates":[-123.30519600,48.46261100]}'
|
||||||
|
chicago_json = '{"type":"Point","crs":{"type":"EPSG","properties":{"EPSG":4326}},"bbox":[-87.65018,41.85039,-87.65018,41.85039],"coordinates":[-87.65018,41.85039]}'
|
||||||
|
|
||||||
|
# Precision argument should only be an integer
|
||||||
|
self.assertRaises(TypeError, City.objects.geojson, precision='foo')
|
||||||
|
|
||||||
|
# Reference queries and values.
|
||||||
|
# SELECT ST_AsGeoJson("geoapp_city"."point", 8, 0) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Pueblo';
|
||||||
|
self.assertEqual(pueblo_json, City.objects.geojson().get(name='Pueblo').geojson)
|
||||||
|
|
||||||
|
# 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
||||||
|
# 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
||||||
|
# This time we want to include the CRS by using the `crs` keyword.
|
||||||
|
self.assertEqual(houston_json, City.objects.geojson(crs=True, model_att='json').get(name='Houston').json)
|
||||||
|
|
||||||
|
# 1.3.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 2) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Victoria';
|
||||||
|
# 1.4.x: SELECT ST_AsGeoJson("geoapp_city"."point", 8, 1) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Houston';
|
||||||
|
# This time we include the bounding box by using the `bbox` keyword.
|
||||||
|
self.assertEqual(victoria_json, City.objects.geojson(bbox=True).get(name='Victoria').geojson)
|
||||||
|
|
||||||
|
# 1.(3|4).x: SELECT ST_AsGeoJson("geoapp_city"."point", 5, 3) FROM "geoapp_city" WHERE "geoapp_city"."name" = 'Chicago';
|
||||||
|
# Finally, we set every available keyword.
|
||||||
|
self.assertEqual(chicago_json, City.objects.geojson(bbox=True, crs=True, precision=5).get(name='Chicago').geojson)
|
||||||
|
|
||||||
|
def test_gml(self):
|
||||||
|
"Testing GML output from the database using GeoQuerySet.gml()."
|
||||||
|
if mysql or (spatialite and not connection.ops.gml) :
|
||||||
|
self.assertRaises(NotImplementedError, Country.objects.all().gml, field_name='mpoly')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Should throw a TypeError when tyring to obtain GML from a
|
||||||
|
# non-geometry field.
|
||||||
|
qs = City.objects.all()
|
||||||
|
self.assertRaises(TypeError, qs.gml, field_name='name')
|
||||||
|
ptown1 = City.objects.gml(field_name='point', precision=9).get(name='Pueblo')
|
||||||
|
ptown2 = City.objects.gml(precision=9).get(name='Pueblo')
|
||||||
|
|
||||||
|
if oracle:
|
||||||
|
# No precision parameter for Oracle :-/
|
||||||
|
gml_regex = re.compile(r'^<gml:Point srsName="SDO:4326" xmlns:gml="http://www.opengis.net/gml"><gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ </gml:coordinates></gml:Point>')
|
||||||
|
elif spatialite:
|
||||||
|
# Spatialite has extra colon in SrsName
|
||||||
|
gml_regex = re.compile(r'^<gml:Point SrsName="EPSG::4326"><gml:coordinates decimal="\." cs="," ts=" ">-104.609251\d+,38.255001</gml:coordinates></gml:Point>')
|
||||||
|
else:
|
||||||
|
gml_regex = re.compile(r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>-104\.60925\d+,38\.255001</gml:coordinates></gml:Point>')
|
||||||
|
|
||||||
|
for ptown in [ptown1, ptown2]:
|
||||||
|
self.assertTrue(gml_regex.match(ptown.gml))
|
||||||
|
|
||||||
|
def test_kml(self):
|
||||||
|
"Testing KML output from the database using GeoQuerySet.kml()."
|
||||||
|
# Only PostGIS and Spatialite (>=2.4.0-RC4) support KML serialization
|
||||||
|
if not (postgis or (spatialite and connection.ops.kml)):
|
||||||
|
self.assertRaises(NotImplementedError, State.objects.all().kml, field_name='poly')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Should throw a TypeError when trying to obtain KML from a
|
||||||
|
# non-geometry field.
|
||||||
|
qs = City.objects.all()
|
||||||
|
self.assertRaises(TypeError, qs.kml, 'name')
|
||||||
|
|
||||||
|
# The reference KML depends on the version of PostGIS used
|
||||||
|
# (the output stopped including altitude in 1.3.3).
|
||||||
|
if connection.ops.spatial_version >= (1, 3, 3):
|
||||||
|
ref_kml = '<Point><coordinates>-104.609252,38.255001</coordinates></Point>'
|
||||||
|
else:
|
||||||
|
ref_kml = '<Point><coordinates>-104.609252,38.255001,0</coordinates></Point>'
|
||||||
|
|
||||||
|
# Ensuring the KML is as expected.
|
||||||
|
ptown1 = City.objects.kml(field_name='point', precision=9).get(name='Pueblo')
|
||||||
|
ptown2 = City.objects.kml(precision=9).get(name='Pueblo')
|
||||||
|
for ptown in [ptown1, ptown2]:
|
||||||
|
self.assertEqual(ref_kml, ptown.kml)
|
||||||
|
|
||||||
|
# Only PostGIS has support for the MakeLine aggregate.
|
||||||
|
@no_mysql
|
||||||
|
@no_oracle
|
||||||
|
@no_spatialite
|
||||||
|
def test_make_line(self):
|
||||||
|
"Testing the `make_line` GeoQuerySet method."
|
||||||
|
# Ensuring that a `TypeError` is raised on models without PointFields.
|
||||||
|
self.assertRaises(TypeError, State.objects.make_line)
|
||||||
|
self.assertRaises(TypeError, Country.objects.make_line)
|
||||||
|
# Reference query:
|
||||||
|
# SELECT AsText(ST_MakeLine(geoapp_city.point)) FROM geoapp_city;
|
||||||
|
ref_line = GEOSGeometry('LINESTRING(-95.363151 29.763374,-96.801611 32.782057,-97.521157 34.464642,174.783117 -41.315268,-104.609252 38.255001,-95.23506 38.971823,-87.650175 41.850385,-123.305196 48.462611)', srid=4326)
|
||||||
|
self.assertEqual(ref_line, City.objects.make_line())
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
def test_num_geom(self):
|
||||||
|
"Testing the `num_geom` GeoQuerySet method."
|
||||||
|
# Both 'countries' only have two geometries.
|
||||||
|
for c in Country.objects.num_geom(): self.assertEqual(2, c.num_geom)
|
||||||
|
for c in City.objects.filter(point__isnull=False).num_geom():
|
||||||
|
# Oracle will return 1 for the number of geometries on non-collections,
|
||||||
|
# whereas PostGIS will return None.
|
||||||
|
if postgis:
|
||||||
|
self.assertEqual(None, c.num_geom)
|
||||||
|
else:
|
||||||
|
self.assertEqual(1, c.num_geom)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_spatialite # SpatiaLite can only count vertices in LineStrings
|
||||||
|
def test_num_points(self):
|
||||||
|
"Testing the `num_points` GeoQuerySet method."
|
||||||
|
for c in Country.objects.num_points():
|
||||||
|
self.assertEqual(c.mpoly.num_points, c.num_points)
|
||||||
|
|
||||||
|
if not oracle:
|
||||||
|
# Oracle cannot count vertices in Point geometries.
|
||||||
|
for c in City.objects.num_points(): self.assertEqual(1, c.num_points)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
def test_point_on_surface(self):
|
||||||
|
"Testing the `point_on_surface` GeoQuerySet method."
|
||||||
|
# Reference values.
|
||||||
|
if oracle:
|
||||||
|
# SELECT SDO_UTIL.TO_WKTGEOMETRY(SDO_GEOM.SDO_POINTONSURFACE(GEOAPP_COUNTRY.MPOLY, 0.05)) FROM GEOAPP_COUNTRY;
|
||||||
|
ref = {'New Zealand' : fromstr('POINT (174.616364 -36.100861)', srid=4326),
|
||||||
|
'Texas' : fromstr('POINT (-103.002434 36.500397)', srid=4326),
|
||||||
|
}
|
||||||
|
|
||||||
|
elif postgis or spatialite:
|
||||||
|
# Using GEOSGeometry to compute the reference point on surface values
|
||||||
|
# -- since PostGIS also uses GEOS these should be the same.
|
||||||
|
ref = {'New Zealand' : Country.objects.get(name='New Zealand').mpoly.point_on_surface,
|
||||||
|
'Texas' : Country.objects.get(name='Texas').mpoly.point_on_surface
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in Country.objects.point_on_surface():
|
||||||
|
if spatialite:
|
||||||
|
# XXX This seems to be a WKT-translation-related precision issue?
|
||||||
|
tol = 0.00001
|
||||||
|
else:
|
||||||
|
tol = 0.000000001
|
||||||
|
self.assertEqual(True, ref[c.name].equals_exact(c.point_on_surface, tol))
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_spatialite
|
||||||
|
def test_reverse_geom(self):
|
||||||
|
"Testing GeoQuerySet.reverse_geom()."
|
||||||
|
coords = [ (-95.363151, 29.763374), (-95.448601, 29.713803) ]
|
||||||
|
Track.objects.create(name='Foo', line=LineString(coords))
|
||||||
|
t = Track.objects.reverse_geom().get(name='Foo')
|
||||||
|
coords.reverse()
|
||||||
|
self.assertEqual(tuple(coords), t.reverse_geom.coords)
|
||||||
|
if oracle:
|
||||||
|
self.assertRaises(TypeError, State.objects.reverse_geom)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_oracle
|
||||||
|
def test_scale(self):
|
||||||
|
"Testing the `scale` GeoQuerySet method."
|
||||||
|
xfac, yfac = 2, 3
|
||||||
|
tol = 5 # XXX The low precision tolerance is for SpatiaLite
|
||||||
|
qs = Country.objects.scale(xfac, yfac, model_att='scaled')
|
||||||
|
for c in qs:
|
||||||
|
for p1, p2 in zip(c.mpoly, c.scaled):
|
||||||
|
for r1, r2 in zip(p1, p2):
|
||||||
|
for c1, c2 in zip(r1.coords, r2.coords):
|
||||||
|
self.assertAlmostEqual(c1[0] * xfac, c2[0], tol)
|
||||||
|
self.assertAlmostEqual(c1[1] * yfac, c2[1], tol)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_oracle
|
||||||
|
@no_spatialite
|
||||||
|
def test_snap_to_grid(self):
|
||||||
"Testing GeoQuerySet.snap_to_grid()."
|
"Testing GeoQuerySet.snap_to_grid()."
|
||||||
# Let's try and break snap_to_grid() with bad combinations of arguments.
|
# Let's try and break snap_to_grid() with bad combinations of arguments.
|
||||||
for bad_args in ((), range(3), range(5)):
|
for bad_args in ((), range(3), range(5)):
|
||||||
|
@ -695,48 +672,78 @@ class GeoModelTest(TestCase):
|
||||||
ref = fromstr('MULTIPOLYGON(((12.4 43.87,12.45 43.87,12.45 44.1,12.5 44.1,12.5 43.87,12.45 43.87,12.4 43.87)))')
|
ref = fromstr('MULTIPOLYGON(((12.4 43.87,12.45 43.87,12.45 44.1,12.5 44.1,12.5 43.87,12.45 43.87,12.4 43.87)))')
|
||||||
self.assertTrue(ref.equals_exact(Country.objects.snap_to_grid(0.05, 0.23, 0.5, 0.17).get(name='San Marino').snap_to_grid, tol))
|
self.assertTrue(ref.equals_exact(Country.objects.snap_to_grid(0.05, 0.23, 0.5, 0.17).get(name='San Marino').snap_to_grid, tol))
|
||||||
|
|
||||||
|
def test_svg(self):
|
||||||
|
"Testing SVG output using GeoQuerySet.svg()."
|
||||||
|
if mysql or oracle:
|
||||||
|
self.assertRaises(NotImplementedError, City.objects.svg)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, City.objects.svg, precision='foo')
|
||||||
|
# SELECT AsSVG(geoapp_city.point, 0, 8) FROM geoapp_city WHERE name = 'Pueblo';
|
||||||
|
svg1 = 'cx="-104.609252" cy="-38.255001"'
|
||||||
|
# Even though relative, only one point so it's practically the same except for
|
||||||
|
# the 'c' letter prefix on the x,y values.
|
||||||
|
svg2 = svg1.replace('c', '')
|
||||||
|
self.assertEqual(svg1, City.objects.svg().get(name='Pueblo').svg)
|
||||||
|
self.assertEqual(svg2, City.objects.svg(relative=5).get(name='Pueblo').svg)
|
||||||
|
|
||||||
@no_mysql
|
@no_mysql
|
||||||
@no_spatialite
|
def test_transform(self):
|
||||||
def test28_reverse(self):
|
"Testing the transform() GeoQuerySet method."
|
||||||
"Testing GeoQuerySet.reverse_geom()."
|
# Pre-transformed points for Houston and Pueblo.
|
||||||
coords = [ (-95.363151, 29.763374), (-95.448601, 29.713803) ]
|
htown = fromstr('POINT(1947516.83115183 6322297.06040572)', srid=3084)
|
||||||
Track.objects.create(name='Foo', line=LineString(coords))
|
ptown = fromstr('POINT(992363.390841912 481455.395105533)', srid=2774)
|
||||||
t = Track.objects.reverse_geom().get(name='Foo')
|
prec = 3 # Precision is low due to version variations in PROJ and GDAL.
|
||||||
coords.reverse()
|
|
||||||
self.assertEqual(tuple(coords), t.reverse_geom.coords)
|
# Asserting the result of the transform operation with the values in
|
||||||
|
# the pre-transformed points. Oracle does not have the 3084 SRID.
|
||||||
|
if not oracle:
|
||||||
|
h = City.objects.transform(htown.srid).get(name='Houston')
|
||||||
|
self.assertEqual(3084, h.point.srid)
|
||||||
|
self.assertAlmostEqual(htown.x, h.point.x, prec)
|
||||||
|
self.assertAlmostEqual(htown.y, h.point.y, prec)
|
||||||
|
|
||||||
|
p1 = City.objects.transform(ptown.srid, field_name='point').get(name='Pueblo')
|
||||||
|
p2 = City.objects.transform(srid=ptown.srid).get(name='Pueblo')
|
||||||
|
for p in [p1, p2]:
|
||||||
|
self.assertEqual(2774, p.point.srid)
|
||||||
|
self.assertAlmostEqual(ptown.x, p.point.x, prec)
|
||||||
|
self.assertAlmostEqual(ptown.y, p.point.y, prec)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
@no_oracle
|
||||||
|
def test_translate(self):
|
||||||
|
"Testing the `translate` GeoQuerySet method."
|
||||||
|
xfac, yfac = 5, -23
|
||||||
|
qs = Country.objects.translate(xfac, yfac, model_att='translated')
|
||||||
|
for c in qs:
|
||||||
|
for p1, p2 in zip(c.mpoly, c.translated):
|
||||||
|
for r1, r2 in zip(p1, p2):
|
||||||
|
for c1, c2 in zip(r1.coords, r2.coords):
|
||||||
|
# XXX The low precision is for SpatiaLite
|
||||||
|
self.assertAlmostEqual(c1[0] + xfac, c2[0], 5)
|
||||||
|
self.assertAlmostEqual(c1[1] + yfac, c2[1], 5)
|
||||||
|
|
||||||
|
@no_mysql
|
||||||
|
def test_unionagg(self):
|
||||||
|
"Testing the `unionagg` (aggregate union) GeoQuerySet method."
|
||||||
|
tx = Country.objects.get(name='Texas').mpoly
|
||||||
|
# Houston, Dallas -- Oracle has different order.
|
||||||
|
union1 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
|
||||||
|
union2 = fromstr('MULTIPOINT(-96.801611 32.782057,-95.363151 29.763374)')
|
||||||
|
qs = City.objects.filter(point__within=tx)
|
||||||
|
self.assertRaises(TypeError, qs.unionagg, 'name')
|
||||||
|
# Using `field_name` keyword argument in one query and specifying an
|
||||||
|
# order in the other (which should not be used because this is
|
||||||
|
# an aggregate method on a spatial column)
|
||||||
|
u1 = qs.unionagg(field_name='point')
|
||||||
|
u2 = qs.order_by('name').unionagg()
|
||||||
|
tol = 0.00001
|
||||||
if oracle:
|
if oracle:
|
||||||
self.assertRaises(TypeError, State.objects.reverse_geom)
|
union = union2
|
||||||
|
else:
|
||||||
@no_mysql
|
union = union1
|
||||||
@no_oracle
|
self.assertEqual(True, union.equals_exact(u1, tol))
|
||||||
@no_spatialite
|
self.assertEqual(True, union.equals_exact(u2, tol))
|
||||||
def test29_force_rhr(self):
|
qs = City.objects.filter(name='NotACity')
|
||||||
"Testing GeoQuerySet.force_rhr()."
|
self.assertEqual(None, qs.unionagg(field_name='point'))
|
||||||
rings = ( ( (0, 0), (5, 0), (0, 5), (0, 0) ),
|
|
||||||
( (1, 1), (1, 3), (3, 1), (1, 1) ),
|
|
||||||
)
|
|
||||||
rhr_rings = ( ( (0, 0), (0, 5), (5, 0), (0, 0) ),
|
|
||||||
( (1, 1), (3, 1), (1, 3), (1, 1) ),
|
|
||||||
)
|
|
||||||
State.objects.create(name='Foo', poly=Polygon(*rings))
|
|
||||||
s = State.objects.force_rhr().get(name='Foo')
|
|
||||||
self.assertEqual(rhr_rings, s.force_rhr.coords)
|
|
||||||
|
|
||||||
@no_mysql
|
|
||||||
@no_oracle
|
|
||||||
@no_spatialite
|
|
||||||
def test30_geohash(self):
|
|
||||||
"Testing GeoQuerySet.geohash()."
|
|
||||||
if not connection.ops.geohash: return
|
|
||||||
# Reference query:
|
|
||||||
# SELECT ST_GeoHash(point) FROM geoapp_city WHERE name='Houston';
|
|
||||||
# SELECT ST_GeoHash(point, 5) FROM geoapp_city WHERE name='Houston';
|
|
||||||
ref_hash = '9vk1mfq8jx0c8e0386z6'
|
|
||||||
h1 = City.objects.geohash().get(name='Houston')
|
|
||||||
h2 = City.objects.geohash(precision=5).get(name='Houston')
|
|
||||||
self.assertEqual(ref_hash, h1.geohash)
|
|
||||||
self.assertEqual(ref_hash[:5], h2.geohash)
|
|
||||||
|
|
||||||
from .test_feeds import GeoFeedTest
|
|
||||||
from .test_regress import GeoRegressionTests
|
|
||||||
from .test_sitemaps import GeoSitemapTest
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from datetime import date, datetime
|
||||||
from django import template
|
from django import template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.template import defaultfilters
|
from django.template import defaultfilters
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils.formats import number_format
|
from django.utils.formats import number_format
|
||||||
from django.utils.translation import pgettext, ungettext, ugettext as _
|
from django.utils.translation import pgettext, ungettext, ugettext as _
|
||||||
from django.utils.timezone import is_aware, utc
|
from django.utils.timezone import is_aware, utc
|
||||||
|
@ -41,7 +41,7 @@ def intcomma(value, use_l10n=True):
|
||||||
return intcomma(value, False)
|
return intcomma(value, False)
|
||||||
else:
|
else:
|
||||||
return number_format(value, force_grouping=True)
|
return number_format(value, force_grouping=True)
|
||||||
orig = force_unicode(value)
|
orig = force_text(value)
|
||||||
new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
|
new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
|
||||||
if orig == new:
|
if orig == new:
|
||||||
return new
|
return new
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.contrib.localflavor.au.au_states import STATE_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select
|
from django.forms.fields import Field, RegexField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class AUPhoneNumberField(Field):
|
||||||
super(AUPhoneNumberField, self).clean(value)
|
super(AUPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\(|\)|\s+|-)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+|-)', '', smart_text(value))
|
||||||
phone_match = PHONE_DIGITS_RE.search(value)
|
phone_match = PHONE_DIGITS_RE.search(value)
|
||||||
if phone_match:
|
if phone_match:
|
||||||
return '%s' % phone_match.group(1)
|
return '%s' % phone_match.group(1)
|
||||||
|
|
|
@ -11,7 +11,7 @@ from django.contrib.localflavor.br.br_states import STATE_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, CharField, Select
|
from django.forms.fields import Field, RegexField, CharField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class BRPhoneNumberField(Field):
|
||||||
super(BRPhoneNumberField, self).clean(value)
|
super(BRPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
||||||
|
@ -68,10 +68,10 @@ class BRStateChoiceField(Field):
|
||||||
value = super(BRStateChoiceField, self).clean(value)
|
value = super(BRStateChoiceField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
value = ''
|
value = ''
|
||||||
value = smart_unicode(value)
|
value = smart_text(value)
|
||||||
if value == '':
|
if value == '':
|
||||||
return value
|
return value
|
||||||
valid_values = set([smart_unicode(k) for k, v in self.widget.choices])
|
valid_values = set([smart_text(k) for k, v in self.widget.choices])
|
||||||
if value not in valid_values:
|
if value not in valid_values:
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return value
|
return value
|
||||||
|
@ -154,10 +154,10 @@ class BRCNPJField(Field):
|
||||||
raise ValidationError(self.error_messages['max_digits'])
|
raise ValidationError(self.error_messages['max_digits'])
|
||||||
orig_dv = value[-2:]
|
orig_dv = value[-2:]
|
||||||
|
|
||||||
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
|
new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(list(range(5, 1, -1)) + list(range(9, 1, -1)))])
|
||||||
new_1dv = DV_maker(new_1dv % 11)
|
new_1dv = DV_maker(new_1dv % 11)
|
||||||
value = value[:-2] + str(new_1dv) + value[-1]
|
value = value[:-2] + str(new_1dv) + value[-1]
|
||||||
new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(6, 1, -1) + range(9, 1, -1))])
|
new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(list(range(6, 1, -1)) + list(range(9, 1, -1)))])
|
||||||
new_2dv = DV_maker(new_2dv % 11)
|
new_2dv = DV_maker(new_2dv % 11)
|
||||||
value = value[:-1] + str(new_2dv)
|
value = value[:-1] + str(new_2dv)
|
||||||
if value[-2:] != orig_dv:
|
if value[-2:] != orig_dv:
|
||||||
|
|
|
@ -9,7 +9,7 @@ import re
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, CharField, Select
|
from django.forms.fields import Field, CharField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class CAPhoneNumberField(Field):
|
||||||
super(CAPhoneNumberField, self).clean(value)
|
super(CAPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.contrib.localflavor.ch.ch_states import STATE_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select
|
from django.forms.fields import Field, RegexField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class CHPhoneNumberField(Field):
|
||||||
super(CHPhoneNumberField, self).clean(value)
|
super(CHPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\.|\s|/|-)', '', smart_unicode(value))
|
value = re.sub('(\.|\s|/|-)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
|
return '%s %s %s %s' % (value[0:3], value[3:6], value[6:8], value[8:10])
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import RegexField, Select
|
from django.forms.fields import RegexField, Select
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
from .cl_regions import REGION_CHOICES
|
from .cl_regions import REGION_CHOICES
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ class CLRutField(RegexField):
|
||||||
Turns the RUT into one normalized format. Returns a (rut, verifier)
|
Turns the RUT into one normalized format. Returns a (rut, verifier)
|
||||||
tuple.
|
tuple.
|
||||||
"""
|
"""
|
||||||
rut = smart_unicode(rut).replace(' ', '').replace('.', '').replace('-', '')
|
rut = smart_text(rut).replace(' ', '').replace('.', '').replace('-', '')
|
||||||
return rut[:-1], rut[-1].upper()
|
return rut[:-1], rut[-1].upper()
|
||||||
|
|
||||||
def _format(self, code, verifier=None):
|
def _format(self, code, verifier=None):
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.contrib.localflavor.fr.fr_department import DEPARTMENT_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import CharField, RegexField, Select
|
from django.forms.fields import CharField, RegexField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class FRPhoneNumberField(CharField):
|
||||||
super(FRPhoneNumberField, self).clean(value)
|
super(FRPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\.|\s)', '', smart_unicode(value))
|
value = re.sub('(\.|\s)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
|
return '%s %s %s %s %s' % (value[0:2], value[2:4], value[4:6], value[6:8], value[8:10])
|
||||||
|
|
|
@ -8,7 +8,7 @@ import re
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import CharField
|
from django.forms import CharField
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class HKPhoneNumberField(CharField):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
value = re.sub('(\(|\)|\s+|\+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+|\+)', '', smart_text(value))
|
||||||
m = hk_phone_digits_re.search(value)
|
m = hk_phone_digits_re.search(value)
|
||||||
if not m:
|
if not m:
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.contrib.localflavor.hr.hr_choices import (
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, Select, RegexField
|
from django.forms.fields import Field, Select, RegexField
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ class HRLicensePlateField(Field):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
value = re.sub(r'[\s\-]+', '', smart_unicode(value.strip())).upper()
|
value = re.sub(r'[\s\-]+', '', smart_text(value.strip())).upper()
|
||||||
|
|
||||||
matches = plate_re.search(value)
|
matches = plate_re.search(value)
|
||||||
if matches is None:
|
if matches is None:
|
||||||
|
@ -225,7 +225,7 @@ class HRPhoneNumberField(Field):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
value = re.sub(r'[\-\s\(\)]', '', smart_unicode(value))
|
value = re.sub(r'[\-\s\(\)]', '', smart_text(value))
|
||||||
|
|
||||||
matches = phone_re.search(value)
|
matches = phone_re.search(value)
|
||||||
if matches is None:
|
if matches is None:
|
||||||
|
|
|
@ -11,7 +11,7 @@ from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, Select
|
from django.forms.fields import Field, Select
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
|
|
||||||
postcode_re = re.compile(r'^[1-9]\d{4}$')
|
postcode_re = re.compile(r'^[1-9]\d{4}$')
|
||||||
|
@ -77,10 +77,10 @@ class IDPhoneNumberField(Field):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
phone_number = re.sub(r'[\-\s\(\)]', '', smart_unicode(value))
|
phone_number = re.sub(r'[\-\s\(\)]', '', smart_text(value))
|
||||||
|
|
||||||
if phone_re.search(phone_number):
|
if phone_re.search(phone_number):
|
||||||
return smart_unicode(value)
|
return smart_text(value)
|
||||||
|
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ class IDLicensePlateField(Field):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
plate_number = re.sub(r'\s+', ' ',
|
plate_number = re.sub(r'\s+', ' ',
|
||||||
smart_unicode(value.strip())).upper()
|
smart_text(value.strip())).upper()
|
||||||
|
|
||||||
matches = plate_re.search(plate_number)
|
matches = plate_re.search(plate_number)
|
||||||
if matches is None:
|
if matches is None:
|
||||||
|
@ -181,7 +181,7 @@ class IDNationalIdentityNumberField(Field):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
value = re.sub(r'[\s.]', '', smart_unicode(value))
|
value = re.sub(r'[\s.]', '', smart_text(value))
|
||||||
|
|
||||||
if not nik_re.search(value):
|
if not nik_re.search(value):
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.contrib.localflavor.in_.in_states import STATES_NORMALIZED, STATE_CH
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, CharField, Select
|
from django.forms.fields import Field, RegexField, CharField, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class INStateField(Field):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return smart_unicode(STATES_NORMALIZED[value.strip().lower()])
|
return smart_text(STATES_NORMALIZED[value.strip().lower()])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
@ -107,7 +107,7 @@ class INPhoneNumberField(CharField):
|
||||||
super(INPhoneNumberField, self).clean(value)
|
super(INPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = smart_unicode(value)
|
value = smart_text(value)
|
||||||
m = phone_digits_re.match(value)
|
m = phone_digits_re.match(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s' % (value)
|
return '%s' % (value)
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import RegexField
|
from django.forms.fields import RegexField
|
||||||
from django.forms.widgets import Select
|
from django.forms.widgets import Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class ISIdNumberField(RegexField):
|
||||||
Takes in the value in canonical form and returns it in the common
|
Takes in the value in canonical form and returns it in the common
|
||||||
display format.
|
display format.
|
||||||
"""
|
"""
|
||||||
return smart_unicode(value[:6]+'-'+value[6:])
|
return smart_text(value[:6]+'-'+value[6:])
|
||||||
|
|
||||||
class ISPhoneNumberField(RegexField):
|
class ISPhoneNumberField(RegexField):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -13,7 +13,7 @@ from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select
|
from django.forms.fields import Field, RegexField, Select
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
|
|
||||||
class ITZipCodeField(RegexField):
|
class ITZipCodeField(RegexField):
|
||||||
|
@ -85,4 +85,4 @@ class ITVatNumberField(Field):
|
||||||
check_digit = vat_number_check_digit(vat_number[0:10])
|
check_digit = vat_number_check_digit(vat_number[0:10])
|
||||||
if not vat_number[10] == check_digit:
|
if not vat_number[10] == check_digit:
|
||||||
raise ValidationError(self.error_messages['invalid'])
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
return smart_unicode(vat_number)
|
return smart_text(vat_number)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
def ssn_check_digit(value):
|
def ssn_check_digit(value):
|
||||||
"Calculate Italian social security number check digit."
|
"Calculate Italian social security number check digit."
|
||||||
|
@ -34,11 +34,11 @@ def ssn_check_digit(value):
|
||||||
|
|
||||||
def vat_number_check_digit(vat_number):
|
def vat_number_check_digit(vat_number):
|
||||||
"Calculate Italian VAT number check digit."
|
"Calculate Italian VAT number check digit."
|
||||||
normalized_vat_number = smart_unicode(vat_number).zfill(10)
|
normalized_vat_number = smart_text(vat_number).zfill(10)
|
||||||
total = 0
|
total = 0
|
||||||
for i in range(0, 10, 2):
|
for i in range(0, 10, 2):
|
||||||
total += int(normalized_vat_number[i])
|
total += int(normalized_vat_number[i])
|
||||||
for i in range(1, 11, 2):
|
for i in range(1, 11, 2):
|
||||||
quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
|
quotient , remainder = divmod(int(normalized_vat_number[i]) * 2, 10)
|
||||||
total += quotient + remainder
|
total += quotient + remainder
|
||||||
return smart_unicode((10 - total % 10) % 10)
|
return smart_text((10 - total % 10) % 10)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.contrib.localflavor.nl.nl_provinces import PROVINCE_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, Select
|
from django.forms.fields import Field, Select
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class NLPhoneNumberField(Field):
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
phone_nr = re.sub('[\-\s\(\)]', '', smart_unicode(value))
|
phone_nr = re.sub('[\-\s\(\)]', '', smart_text(value))
|
||||||
|
|
||||||
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
|
if len(phone_nr) == 10 and numeric_re.search(phone_nr):
|
||||||
return value
|
return value
|
||||||
|
|
|
@ -8,7 +8,7 @@ import re
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField
|
from django.forms.fields import Field, RegexField
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
phone_digits_re = re.compile(r'^(\d{9}|(00|\+)\d*)$')
|
phone_digits_re = re.compile(r'^(\d{9}|(00|\+)\d*)$')
|
||||||
|
@ -43,7 +43,7 @@ class PTPhoneNumberField(Field):
|
||||||
super(PTPhoneNumberField, self).clean(value)
|
super(PTPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\.|\s)', '', smart_unicode(value))
|
value = re.sub('(\.|\s)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s' % value
|
return '%s' % value
|
||||||
|
|
|
@ -41,7 +41,7 @@ class SIEMSOField(CharField):
|
||||||
# Validate EMSO
|
# Validate EMSO
|
||||||
s = 0
|
s = 0
|
||||||
int_values = [int(i) for i in value]
|
int_values = [int(i) for i in value]
|
||||||
for a, b in zip(int_values, range(7, 1, -1) * 2):
|
for a, b in zip(int_values, list(range(7, 1, -1)) * 2):
|
||||||
s += a * b
|
s += a * b
|
||||||
chk = s % 11
|
chk = s % 11
|
||||||
if chk == 0:
|
if chk == 0:
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.contrib.localflavor.tr.tr_provinces import PROVINCE_CHOICES
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select, CharField
|
from django.forms.fields import Field, RegexField, Select, CharField
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class TRPhoneNumberField(CharField):
|
||||||
super(TRPhoneNumberField, self).clean(value)
|
super(TRPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s%s' % (m.group(2), m.group(4))
|
return '%s%s' % (m.group(2), m.group(4))
|
||||||
|
|
|
@ -9,7 +9,7 @@ import re
|
||||||
from django.core.validators import EMPTY_VALUES
|
from django.core.validators import EMPTY_VALUES
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.forms.fields import Field, RegexField, Select, CharField
|
from django.forms.fields import Field, RegexField, Select, CharField
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class USPhoneNumberField(CharField):
|
||||||
super(USPhoneNumberField, self).clean(value)
|
super(USPhoneNumberField, self).clean(value)
|
||||||
if value in EMPTY_VALUES:
|
if value in EMPTY_VALUES:
|
||||||
return ''
|
return ''
|
||||||
value = re.sub('(\(|\)|\s+)', '', smart_unicode(value))
|
value = re.sub('(\(|\)|\s+)', '', smart_text(value))
|
||||||
m = phone_digits_re.search(value)
|
m = phone_digits_re.search(value)
|
||||||
if m:
|
if m:
|
||||||
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
return '%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
|
||||||
|
|
|
@ -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_str, force_unicode
|
from django.utils.encoding import smart_bytes, force_text
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
@ -25,9 +25,9 @@ def textile(value):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
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_unicode(value)
|
return force_text(value)
|
||||||
else:
|
else:
|
||||||
return mark_safe(force_unicode(textile.textile(smart_str(value), encoding='utf-8', output='utf-8')))
|
return mark_safe(force_text(textile.textile(smart_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=''):
|
||||||
|
@ -52,23 +52,23 @@ def markdown(value, arg=''):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
raise template.TemplateSyntaxError("Error in 'markdown' filter: The Python markdown library isn't installed.")
|
raise template.TemplateSyntaxError("Error in 'markdown' filter: The Python markdown library isn't installed.")
|
||||||
return force_unicode(value)
|
return force_text(value)
|
||||||
else:
|
else:
|
||||||
markdown_vers = getattr(markdown, "version_info", 0)
|
markdown_vers = getattr(markdown, "version_info", 0)
|
||||||
if markdown_vers < (2, 1):
|
if markdown_vers < (2, 1):
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
raise template.TemplateSyntaxError(
|
raise template.TemplateSyntaxError(
|
||||||
"Error in 'markdown' filter: Django does not support versions of the Python markdown library < 2.1.")
|
"Error in 'markdown' filter: Django does not support versions of the Python markdown library < 2.1.")
|
||||||
return force_unicode(value)
|
return force_text(value)
|
||||||
else:
|
else:
|
||||||
extensions = [e for e in arg.split(",") if e]
|
extensions = [e for e in arg.split(",") if e]
|
||||||
if extensions and extensions[0] == "safe":
|
if extensions and extensions[0] == "safe":
|
||||||
extensions = extensions[1:]
|
extensions = extensions[1:]
|
||||||
return mark_safe(markdown.markdown(
|
return mark_safe(markdown.markdown(
|
||||||
force_unicode(value), extensions, safe_mode=True, enable_attributes=False))
|
force_text(value), extensions, safe_mode=True, enable_attributes=False))
|
||||||
else:
|
else:
|
||||||
return mark_safe(markdown.markdown(
|
return mark_safe(markdown.markdown(
|
||||||
force_unicode(value), extensions, safe_mode=False))
|
force_text(value), extensions, safe_mode=False))
|
||||||
|
|
||||||
@register.filter(is_safe=True)
|
@register.filter(is_safe=True)
|
||||||
def restructuredtext(value):
|
def restructuredtext(value):
|
||||||
|
@ -77,8 +77,8 @@ def restructuredtext(value):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
raise template.TemplateSyntaxError("Error in 'restructuredtext' filter: The Python docutils library isn't installed.")
|
raise template.TemplateSyntaxError("Error in 'restructuredtext' filter: The Python docutils library isn't installed.")
|
||||||
return force_unicode(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_str(value), writer_name="html4css1", settings_overrides=docutils_settings)
|
parts = publish_parts(source=smart_bytes(value), writer_name="html4css1", settings_overrides=docutils_settings)
|
||||||
return mark_safe(force_unicode(parts["fragment"]))
|
return mark_safe(force_text(parts["fragment"]))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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_unicode, StrAndUnicode
|
from django.utils.encoding import force_text, StrAndUnicode
|
||||||
from django.contrib.messages import constants, utils
|
from django.contrib.messages import constants, utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,22 +26,22 @@ class Message(StrAndUnicode):
|
||||||
and ``extra_tags`` to unicode in case they are lazy translations.
|
and ``extra_tags`` to unicode in case they are lazy translations.
|
||||||
|
|
||||||
Known "safe" types (None, int, etc.) are not converted (see Django's
|
Known "safe" types (None, int, etc.) are not converted (see Django's
|
||||||
``force_unicode`` implementation for details).
|
``force_text`` implementation for details).
|
||||||
"""
|
"""
|
||||||
self.message = force_unicode(self.message, strings_only=True)
|
self.message = force_text(self.message, strings_only=True)
|
||||||
self.extra_tags = force_unicode(self.extra_tags, strings_only=True)
|
self.extra_tags = force_text(self.extra_tags, strings_only=True)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
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 __unicode__(self):
|
||||||
return force_unicode(self.message)
|
return force_text(self.message)
|
||||||
|
|
||||||
def _get_tags(self):
|
def _get_tags(self):
|
||||||
label_tag = force_unicode(LEVEL_TAGS.get(self.level, ''),
|
label_tag = force_text(LEVEL_TAGS.get(self.level, ''),
|
||||||
strings_only=True)
|
strings_only=True)
|
||||||
extra_tags = force_unicode(self.extra_tags, strings_only=True)
|
extra_tags = force_text(self.extra_tags, strings_only=True)
|
||||||
if extra_tags and label_tag:
|
if extra_tags and label_tag:
|
||||||
return ' '.join([extra_tags, label_tag])
|
return ' '.join([extra_tags, label_tag])
|
||||||
elif extra_tags:
|
elif extra_tags:
|
||||||
|
|
|
@ -4,6 +4,7 @@ from django.conf import settings
|
||||||
from django.contrib.messages.storage.base import BaseStorage, Message
|
from django.contrib.messages.storage.base import BaseStorage, Message
|
||||||
from django.http import SimpleCookie
|
from django.http import SimpleCookie
|
||||||
from django.utils.crypto import salted_hmac, constant_time_compare
|
from django.utils.crypto import salted_hmac, constant_time_compare
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
class MessageEncoder(json.JSONEncoder):
|
class MessageEncoder(json.JSONEncoder):
|
||||||
|
@ -33,7 +34,7 @@ class MessageDecoder(json.JSONDecoder):
|
||||||
return [self.process_messages(item) for item in obj]
|
return [self.process_messages(item) for item in obj]
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
return dict([(key, self.process_messages(value))
|
return dict([(key, self.process_messages(value))
|
||||||
for key, value in obj.iteritems()])
|
for key, value in six.iteritems(obj)])
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def decode(self, s, **kwargs):
|
def decode(self, s, **kwargs):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,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_unicode(s.session_data))
|
return self.decode(force_text(s.session_data))
|
||||||
except (Session.DoesNotExist, SuspiciousOperation):
|
except (Session.DoesNotExist, SuspiciousOperation):
|
||||||
self.create()
|
self.create()
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -16,6 +16,7 @@ from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.test import TestCase, RequestFactory
|
from django.test import TestCase, RequestFactory
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
|
|
||||||
|
@ -86,16 +87,16 @@ class SessionTestsMixin(object):
|
||||||
self.assertFalse(self.session.modified)
|
self.assertFalse(self.session.modified)
|
||||||
|
|
||||||
def test_values(self):
|
def test_values(self):
|
||||||
self.assertEqual(self.session.values(), [])
|
self.assertEqual(list(self.session.values()), [])
|
||||||
self.assertTrue(self.session.accessed)
|
self.assertTrue(self.session.accessed)
|
||||||
self.session['some key'] = 1
|
self.session['some key'] = 1
|
||||||
self.assertEqual(self.session.values(), [1])
|
self.assertEqual(list(self.session.values()), [1])
|
||||||
|
|
||||||
def test_iterkeys(self):
|
def test_iterkeys(self):
|
||||||
self.session['x'] = 1
|
self.session['x'] = 1
|
||||||
self.session.modified = False
|
self.session.modified = False
|
||||||
self.session.accessed = False
|
self.session.accessed = False
|
||||||
i = self.session.iterkeys()
|
i = six.iterkeys(self.session)
|
||||||
self.assertTrue(hasattr(i, '__iter__'))
|
self.assertTrue(hasattr(i, '__iter__'))
|
||||||
self.assertTrue(self.session.accessed)
|
self.assertTrue(self.session.accessed)
|
||||||
self.assertFalse(self.session.modified)
|
self.assertFalse(self.session.modified)
|
||||||
|
@ -105,7 +106,7 @@ class SessionTestsMixin(object):
|
||||||
self.session['x'] = 1
|
self.session['x'] = 1
|
||||||
self.session.modified = False
|
self.session.modified = False
|
||||||
self.session.accessed = False
|
self.session.accessed = False
|
||||||
i = self.session.itervalues()
|
i = six.itervalues(self.session)
|
||||||
self.assertTrue(hasattr(i, '__iter__'))
|
self.assertTrue(hasattr(i, '__iter__'))
|
||||||
self.assertTrue(self.session.accessed)
|
self.assertTrue(self.session.accessed)
|
||||||
self.assertFalse(self.session.modified)
|
self.assertFalse(self.session.modified)
|
||||||
|
@ -115,7 +116,7 @@ class SessionTestsMixin(object):
|
||||||
self.session['x'] = 1
|
self.session['x'] = 1
|
||||||
self.session.modified = False
|
self.session.modified = False
|
||||||
self.session.accessed = False
|
self.session.accessed = False
|
||||||
i = self.session.iteritems()
|
i = six.iteritems(self.session)
|
||||||
self.assertTrue(hasattr(i, '__iter__'))
|
self.assertTrue(hasattr(i, '__iter__'))
|
||||||
self.assertTrue(self.session.accessed)
|
self.assertTrue(self.session.accessed)
|
||||||
self.assertFalse(self.session.modified)
|
self.assertFalse(self.session.modified)
|
||||||
|
@ -125,9 +126,9 @@ class SessionTestsMixin(object):
|
||||||
self.session['x'] = 1
|
self.session['x'] = 1
|
||||||
self.session.modified = False
|
self.session.modified = False
|
||||||
self.session.accessed = False
|
self.session.accessed = False
|
||||||
self.assertEqual(self.session.items(), [('x', 1)])
|
self.assertEqual(list(self.session.items()), [('x', 1)])
|
||||||
self.session.clear()
|
self.session.clear()
|
||||||
self.assertEqual(self.session.items(), [])
|
self.assertEqual(list(self.session.items()), [])
|
||||||
self.assertTrue(self.session.accessed)
|
self.assertTrue(self.session.accessed)
|
||||||
self.assertTrue(self.session.modified)
|
self.assertTrue(self.session.modified)
|
||||||
|
|
||||||
|
@ -154,10 +155,10 @@ class SessionTestsMixin(object):
|
||||||
self.session['a'], self.session['b'] = 'c', 'd'
|
self.session['a'], self.session['b'] = 'c', 'd'
|
||||||
self.session.save()
|
self.session.save()
|
||||||
prev_key = self.session.session_key
|
prev_key = self.session.session_key
|
||||||
prev_data = self.session.items()
|
prev_data = list(self.session.items())
|
||||||
self.session.cycle_key()
|
self.session.cycle_key()
|
||||||
self.assertNotEqual(self.session.session_key, prev_key)
|
self.assertNotEqual(self.session.session_key, prev_key)
|
||||||
self.assertEqual(self.session.items(), prev_data)
|
self.assertEqual(list(self.session.items()), prev_data)
|
||||||
|
|
||||||
def test_invalid_key(self):
|
def test_invalid_key(self):
|
||||||
# Submitting an invalid session key (either by guessing, or if the db has
|
# Submitting an invalid session key (either by guessing, or if the db has
|
||||||
|
|
|
@ -3,6 +3,7 @@ from django.core import urlresolvers
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
def index(request, sitemaps,
|
def index(request, sitemaps,
|
||||||
template_name='sitemap_index.xml', mimetype='application/xml',
|
template_name='sitemap_index.xml', mimetype='application/xml',
|
||||||
|
@ -35,7 +36,7 @@ def sitemap(request, sitemaps, section=None,
|
||||||
raise Http404("No sitemap available for section: %r" % section)
|
raise Http404("No sitemap available for section: %r" % section)
|
||||||
maps = [sitemaps[section]]
|
maps = [sitemaps[section]]
|
||||||
else:
|
else:
|
||||||
maps = sitemaps.values()
|
maps = list(six.itervalues(sitemaps))
|
||||||
page = request.GET.get("p", 1)
|
page = request.GET.get("p", 1)
|
||||||
|
|
||||||
urls = []
|
urls = []
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.utils.datastructures import SortedDict
|
||||||
from django.utils.functional import empty, memoize, LazyObject
|
from django.utils.functional import empty, memoize, LazyObject
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils._os import safe_join
|
from django.utils._os import safe_join
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
from django.contrib.staticfiles import utils
|
from django.contrib.staticfiles import utils
|
||||||
from django.contrib.staticfiles.storage import AppStaticStorage
|
from django.contrib.staticfiles.storage import AppStaticStorage
|
||||||
|
@ -132,7 +133,7 @@ class AppDirectoriesFinder(BaseFinder):
|
||||||
"""
|
"""
|
||||||
List all files in all app storages.
|
List all files in all app storages.
|
||||||
"""
|
"""
|
||||||
for storage in self.storages.itervalues():
|
for storage in six.itervalues(self.storages):
|
||||||
if storage.exists(''): # check if storage location exists
|
if storage.exists(''): # check if storage location exists
|
||||||
for path in utils.get_files(storage, ignore_patterns):
|
for path in utils.get_files(storage, ignore_patterns):
|
||||||
yield path, storage
|
yield path, storage
|
||||||
|
|
|
@ -6,8 +6,9 @@ from optparse import make_option
|
||||||
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
from django.core.files.storage import FileSystemStorage
|
||||||
from django.core.management.base import CommandError, NoArgsCommand
|
from django.core.management.base import CommandError, NoArgsCommand
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
from django.utils.six.moves import input
|
||||||
|
|
||||||
from django.contrib.staticfiles import finders, storage
|
from django.contrib.staticfiles import finders, storage
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ class Command(NoArgsCommand):
|
||||||
clear_display = 'This will overwrite existing files!'
|
clear_display = 'This will overwrite existing files!'
|
||||||
|
|
||||||
if self.interactive:
|
if self.interactive:
|
||||||
confirm = raw_input("""
|
confirm = input("""
|
||||||
You have requested to collect static files at the destination
|
You have requested to collect static files at the destination
|
||||||
location as specified in your settings%s
|
location as specified in your settings%s
|
||||||
|
|
||||||
|
@ -198,9 +199,9 @@ Type 'yes' to continue, or 'no' to cancel: """
|
||||||
fpath = os.path.join(path, f)
|
fpath = os.path.join(path, f)
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
self.log("Pretending to delete '%s'" %
|
self.log("Pretending to delete '%s'" %
|
||||||
smart_unicode(fpath), level=1)
|
smart_text(fpath), level=1)
|
||||||
else:
|
else:
|
||||||
self.log("Deleting '%s'" % smart_unicode(fpath), level=1)
|
self.log("Deleting '%s'" % smart_text(fpath), level=1)
|
||||||
self.storage.delete(fpath)
|
self.storage.delete(fpath)
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
self.clear_dir(os.path.join(path, d))
|
self.clear_dir(os.path.join(path, d))
|
||||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
from optparse import make_option
|
from optparse import make_option
|
||||||
from django.core.management.base import LabelCommand
|
from django.core.management.base import LabelCommand
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
|
|
||||||
from django.contrib.staticfiles import finders
|
from django.contrib.staticfiles import finders
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@ class Command(LabelCommand):
|
||||||
def handle_label(self, path, **options):
|
def handle_label(self, path, **options):
|
||||||
verbosity = int(options.get('verbosity', 1))
|
verbosity = int(options.get('verbosity', 1))
|
||||||
result = finders.find(path, all=options['all'])
|
result = finders.find(path, all=options['all'])
|
||||||
path = smart_unicode(path)
|
path = smart_text(path)
|
||||||
if result:
|
if result:
|
||||||
if not isinstance(result, (list, tuple)):
|
if not isinstance(result, (list, tuple)):
|
||||||
result = [result]
|
result = [result]
|
||||||
output = '\n '.join(
|
output = '\n '.join(
|
||||||
(smart_unicode(os.path.realpath(path)) for path in result))
|
(smart_text(os.path.realpath(path)) for path in result))
|
||||||
self.stdout.write("Found '%s' here:\n %s" % (path, output))
|
self.stdout.write("Found '%s' here:\n %s" % (path, output))
|
||||||
else:
|
else:
|
||||||
if verbosity >= 1:
|
if verbosity >= 1:
|
||||||
|
|
|
@ -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_unicode, smart_str
|
from django.utils.encoding import force_text, smart_bytes
|
||||||
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
|
||||||
|
|
||||||
|
@ -112,7 +112,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_str(name)).hexdigest()
|
return 'staticfiles:%s' % hashlib.md5(smart_bytes(name)).hexdigest()
|
||||||
|
|
||||||
def url(self, name, force=False):
|
def url(self, name, force=False):
|
||||||
"""
|
"""
|
||||||
|
@ -248,9 +248,9 @@ 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_str(content))
|
content_file = ContentFile(smart_bytes(content))
|
||||||
saved_name = self._save(hashed_name, content_file)
|
saved_name = self._save(hashed_name, content_file)
|
||||||
hashed_name = force_unicode(saved_name.replace('\\', '/'))
|
hashed_name = force_text(saved_name.replace('\\', '/'))
|
||||||
processed = True
|
processed = True
|
||||||
else:
|
else:
|
||||||
# or handle the case in which neither processing nor
|
# or handle the case in which neither processing nor
|
||||||
|
@ -258,7 +258,7 @@ class CachedFilesMixin(object):
|
||||||
if not hashed_file_exists:
|
if not hashed_file_exists:
|
||||||
processed = True
|
processed = True
|
||||||
saved_name = self._save(hashed_name, original_file)
|
saved_name = self._save(hashed_name, original_file)
|
||||||
hashed_name = force_unicode(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)] = hashed_name
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||||
from django.http import HttpResponse, Http404
|
from django.http import HttpResponse, Http404
|
||||||
from django.template import loader, TemplateDoesNotExist, RequestContext
|
from django.template import loader, TemplateDoesNotExist, RequestContext
|
||||||
from django.utils import feedgenerator, tzinfo
|
from django.utils import feedgenerator, tzinfo
|
||||||
from django.utils.encoding import force_unicode, iri_to_uri, smart_unicode
|
from django.utils.encoding import force_text, iri_to_uri, smart_text
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.timezone import is_naive
|
from django.utils.timezone import is_naive
|
||||||
|
|
||||||
|
@ -43,10 +43,10 @@ class Feed(object):
|
||||||
|
|
||||||
def item_title(self, item):
|
def item_title(self, item):
|
||||||
# Titles should be double escaped by default (see #6533)
|
# Titles should be double escaped by default (see #6533)
|
||||||
return escape(force_unicode(item))
|
return escape(force_text(item))
|
||||||
|
|
||||||
def item_description(self, item):
|
def item_description(self, item):
|
||||||
return force_unicode(item)
|
return force_text(item)
|
||||||
|
|
||||||
def item_link(self, item):
|
def item_link(self, item):
|
||||||
try:
|
try:
|
||||||
|
@ -154,9 +154,9 @@ class Feed(object):
|
||||||
enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
|
enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
|
||||||
if enc_url:
|
if enc_url:
|
||||||
enc = feedgenerator.Enclosure(
|
enc = feedgenerator.Enclosure(
|
||||||
url = smart_unicode(enc_url),
|
url = smart_text(enc_url),
|
||||||
length = smart_unicode(self.__get_dynamic_attr('item_enclosure_length', item)),
|
length = smart_text(self.__get_dynamic_attr('item_enclosure_length', item)),
|
||||||
mime_type = smart_unicode(self.__get_dynamic_attr('item_enclosure_mime_type', item))
|
mime_type = smart_text(self.__get_dynamic_attr('item_enclosure_mime_type', item))
|
||||||
)
|
)
|
||||||
author_name = self.__get_dynamic_attr('item_author_name', item)
|
author_name = self.__get_dynamic_attr('item_author_name', item)
|
||||||
if author_name is not None:
|
if author_name is not None:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
|
from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning
|
||||||
from django.utils.encoding import smart_str
|
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_str(key)])
|
return ':'.join([key_prefix, str(version), smart_bytes(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_str(params.get('KEY_PREFIX', ''))
|
self.key_prefix = smart_bytes(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))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ RequestContext.
|
||||||
|
|
||||||
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_str
|
from django.utils.encoding import smart_bytes
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
|
||||||
def csrf(request):
|
def csrf(request):
|
||||||
|
@ -25,7 +25,7 @@ def csrf(request):
|
||||||
# instead of returning an empty dict.
|
# instead of returning an empty dict.
|
||||||
return b'NOTPROVIDED'
|
return b'NOTPROVIDED'
|
||||||
else:
|
else:
|
||||||
return smart_str(token)
|
return smart_bytes(token)
|
||||||
_get_val = lazy(_get_val, str)
|
_get_val = lazy(_get_val, str)
|
||||||
|
|
||||||
return {'csrf_token': _get_val() }
|
return {'csrf_token': _get_val() }
|
||||||
|
|
|
@ -43,7 +43,7 @@ class ValidationError(Exception):
|
||||||
"""An error while validating data."""
|
"""An error while validating data."""
|
||||||
def __init__(self, message, code=None, params=None):
|
def __init__(self, message, code=None, params=None):
|
||||||
import operator
|
import operator
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
"""
|
"""
|
||||||
ValidationError can be passed any object that can be printed (usually
|
ValidationError can be passed any object that can be printed (usually
|
||||||
a string), a list of objects or a dictionary.
|
a string), a list of objects or a dictionary.
|
||||||
|
@ -54,11 +54,11 @@ class ValidationError(Exception):
|
||||||
message = reduce(operator.add, message.values())
|
message = reduce(operator.add, message.values())
|
||||||
|
|
||||||
if isinstance(message, list):
|
if isinstance(message, list):
|
||||||
self.messages = [force_unicode(msg) for msg in message]
|
self.messages = [force_text(msg) for msg in message]
|
||||||
else:
|
else:
|
||||||
self.code = code
|
self.code = code
|
||||||
self.params = params
|
self.params = params
|
||||||
message = force_unicode(message)
|
message = force_text(message)
|
||||||
self.messages = [message]
|
self.messages = [message]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from django.utils.encoding import smart_str, smart_unicode
|
from django.utils.encoding import smart_bytes, smart_text
|
||||||
from django.core.files.utils import FileProxyMixin
|
from django.core.files.utils import FileProxyMixin
|
||||||
|
|
||||||
class File(FileProxyMixin):
|
class File(FileProxyMixin):
|
||||||
|
@ -18,16 +18,17 @@ class File(FileProxyMixin):
|
||||||
self.mode = file.mode
|
self.mode = file.mode
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return smart_str(self.name or '')
|
return smart_bytes(self.name or '')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return smart_unicode(self.name or '')
|
return smart_text(self.name or '')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s: %s>" % (self.__class__.__name__, self or "None")
|
return "<%s: %s>" % (self.__class__.__name__, self or "None")
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return bool(self.name)
|
return bool(self.name)
|
||||||
|
__nonzero__ = __bool__ # Python 2
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return self.size
|
return self.size
|
||||||
|
@ -135,8 +136,9 @@ class ContentFile(File):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Raw content'
|
return 'Raw content'
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return True
|
return True
|
||||||
|
__nonzero__ = __bool__ # Python 2
|
||||||
|
|
||||||
def open(self, mode=None):
|
def open(self, mode=None):
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
|
|
@ -47,13 +47,18 @@ def get_image_dimensions(file_or_path, close=False):
|
||||||
file = open(file_or_path, 'rb')
|
file = open(file_or_path, 'rb')
|
||||||
close = True
|
close = True
|
||||||
try:
|
try:
|
||||||
|
# Most of the time PIL only needs a small chunk to parse the image and
|
||||||
|
# get the dimensions, but with some TIFF files PIL needs to parse the
|
||||||
|
# whole file.
|
||||||
|
chunk_size = 1024
|
||||||
while 1:
|
while 1:
|
||||||
data = file.read(1024)
|
data = file.read(chunk_size)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
p.feed(data)
|
p.feed(data)
|
||||||
if p.image:
|
if p.image:
|
||||||
return p.image.size
|
return p.image.size
|
||||||
|
chunk_size = chunk_size*2
|
||||||
return None
|
return None
|
||||||
finally:
|
finally:
|
||||||
if close:
|
if close:
|
||||||
|
|
|
@ -11,7 +11,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
|
||||||
from django.core.files import locks, File
|
from django.core.files import locks, File
|
||||||
from django.core.files.move import file_move_safe
|
from django.core.files.move import file_move_safe
|
||||||
from django.utils.encoding import force_unicode, filepath_to_uri
|
from django.utils.encoding import force_text, filepath_to_uri
|
||||||
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
|
||||||
from django.utils.text import get_valid_filename
|
from django.utils.text import get_valid_filename
|
||||||
|
@ -48,7 +48,7 @@ class Storage(object):
|
||||||
name = self._save(name, content)
|
name = self._save(name, content)
|
||||||
|
|
||||||
# Store filenames with forward slashes, even on Windows
|
# Store filenames with forward slashes, even on Windows
|
||||||
return force_unicode(name.replace('\\', '/'))
|
return force_text(name.replace('\\', '/'))
|
||||||
|
|
||||||
# These methods are part of the public API, with default implementations.
|
# These methods are part of the public API, with default implementations.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from io import BytesIO
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.base import File
|
from django.core.files.base import File
|
||||||
from django.core.files import temp as tempfile
|
from django.core.files import temp as tempfile
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_bytes
|
||||||
|
|
||||||
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
|
__all__ = ('UploadedFile', 'TemporaryUploadedFile', 'InMemoryUploadedFile',
|
||||||
'SimpleUploadedFile')
|
'SimpleUploadedFile')
|
||||||
|
@ -30,7 +30,7 @@ class UploadedFile(File):
|
||||||
self.charset = charset
|
self.charset = charset
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return smart_str("<%s: %s (%s)>" % (
|
return smart_bytes("<%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):
|
||||||
|
|
|
@ -4,7 +4,7 @@ import sys
|
||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django.core import signals
|
from django.core import signals
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -250,7 +250,7 @@ def get_script_name(environ):
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
if settings.FORCE_SCRIPT_NAME is not None:
|
if settings.FORCE_SCRIPT_NAME is not None:
|
||||||
return force_unicode(settings.FORCE_SCRIPT_NAME)
|
return force_text(settings.FORCE_SCRIPT_NAME)
|
||||||
|
|
||||||
# If Apache's mod_rewrite had a whack at the URL, Apache set either
|
# If Apache's mod_rewrite had a whack at the URL, Apache set either
|
||||||
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
|
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
|
||||||
|
@ -261,5 +261,5 @@ def get_script_name(environ):
|
||||||
if not script_url:
|
if not script_url:
|
||||||
script_url = environ.get('REDIRECT_URL', '')
|
script_url = environ.get('REDIRECT_URL', '')
|
||||||
if script_url:
|
if script_url:
|
||||||
return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
|
return force_text(script_url[:-len(environ.get('PATH_INFO', ''))])
|
||||||
return force_unicode(environ.get('SCRIPT_NAME', ''))
|
return force_text(environ.get('SCRIPT_NAME', ''))
|
||||||
|
|
|
@ -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_unicode, smart_str, iri_to_uri
|
from django.utils.encoding import force_text, smart_bytes, iri_to_uri
|
||||||
from django.utils.log import getLogger
|
from django.utils.log import getLogger
|
||||||
|
|
||||||
logger = getLogger('django.request')
|
logger = getLogger('django.request')
|
||||||
|
@ -127,7 +127,7 @@ class LimitedStream(object):
|
||||||
class WSGIRequest(http.HttpRequest):
|
class WSGIRequest(http.HttpRequest):
|
||||||
def __init__(self, environ):
|
def __init__(self, environ):
|
||||||
script_name = base.get_script_name(environ)
|
script_name = base.get_script_name(environ)
|
||||||
path_info = force_unicode(environ.get('PATH_INFO', '/'))
|
path_info = force_text(environ.get('PATH_INFO', '/'))
|
||||||
if not path_info or path_info == script_name:
|
if not path_info or path_info == script_name:
|
||||||
# Sometimes PATH_INFO exists, but is empty (e.g. accessing
|
# Sometimes PATH_INFO exists, but is empty (e.g. accessing
|
||||||
# the SCRIPT_NAME URL without a trailing slash). We really need to
|
# the SCRIPT_NAME URL without a trailing slash). We really need to
|
||||||
|
@ -245,6 +245,6 @@ class WSGIHandler(base.BaseHandler):
|
||||||
status = '%s %s' % (response.status_code, status_text)
|
status = '%s %s' % (response.status_code, status_text)
|
||||||
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((b'Set-Cookie', str(c.output(header=''))))
|
response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
|
||||||
start_response(smart_str(status), response_headers)
|
start_response(smart_bytes(status), response_headers)
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -11,11 +11,10 @@ from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.base import MIMEBase
|
from email.mime.base import MIMEBase
|
||||||
from email.header import Header
|
from email.header import Header
|
||||||
from email.utils import formatdate, getaddresses, formataddr, parseaddr
|
from email.utils import formatdate, getaddresses, formataddr, parseaddr
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail.utils import DNS_NAME
|
from django.core.mail.utils import DNS_NAME
|
||||||
from django.utils.encoding import smart_str, force_unicode
|
from django.utils.encoding import force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,38 +78,38 @@ ADDRESS_HEADERS = set([
|
||||||
def forbid_multi_line_headers(name, val, encoding):
|
def forbid_multi_line_headers(name, val, encoding):
|
||||||
"""Forbids multi-line headers, to prevent header injection."""
|
"""Forbids multi-line headers, to prevent header injection."""
|
||||||
encoding = encoding or settings.DEFAULT_CHARSET
|
encoding = encoding or settings.DEFAULT_CHARSET
|
||||||
val = force_unicode(val)
|
val = force_text(val)
|
||||||
if '\n' in val or '\r' in val:
|
if '\n' in val or '\r' in val:
|
||||||
raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
|
raise BadHeaderError("Header values can't contain newlines (got %r for header %r)" % (val, name))
|
||||||
try:
|
try:
|
||||||
val = val.encode('ascii')
|
val.encode('ascii')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
if name.lower() in ADDRESS_HEADERS:
|
if name.lower() in ADDRESS_HEADERS:
|
||||||
val = ', '.join(sanitize_address(addr, encoding)
|
val = ', '.join(sanitize_address(addr, encoding)
|
||||||
for addr in getaddresses((val,)))
|
for addr in getaddresses((val,)))
|
||||||
else:
|
else:
|
||||||
val = str(Header(val, encoding))
|
val = Header(val, encoding).encode()
|
||||||
else:
|
else:
|
||||||
if name.lower() == 'subject':
|
if name.lower() == 'subject':
|
||||||
val = Header(val)
|
val = Header(val).encode()
|
||||||
return smart_str(name), val
|
return str(name), val
|
||||||
|
|
||||||
|
|
||||||
def sanitize_address(addr, encoding):
|
def sanitize_address(addr, encoding):
|
||||||
if isinstance(addr, six.string_types):
|
if isinstance(addr, six.string_types):
|
||||||
addr = parseaddr(force_unicode(addr))
|
addr = parseaddr(force_text(addr))
|
||||||
nm, addr = addr
|
nm, addr = addr
|
||||||
nm = str(Header(nm, encoding))
|
nm = Header(nm, encoding).encode()
|
||||||
try:
|
try:
|
||||||
addr = addr.encode('ascii')
|
addr.encode('ascii')
|
||||||
except UnicodeEncodeError: # IDN
|
except UnicodeEncodeError: # IDN
|
||||||
if '@' in addr:
|
if '@' in addr:
|
||||||
localpart, domain = addr.split('@', 1)
|
localpart, domain = addr.split('@', 1)
|
||||||
localpart = str(Header(localpart, encoding))
|
localpart = str(Header(localpart, encoding))
|
||||||
domain = domain.encode('idna')
|
domain = domain.encode('idna').decode('ascii')
|
||||||
addr = '@'.join([localpart, domain])
|
addr = '@'.join([localpart, domain])
|
||||||
else:
|
else:
|
||||||
addr = str(Header(addr, encoding))
|
addr = Header(addr, encoding).encode()
|
||||||
return formataddr((nm, addr))
|
return formataddr((nm, addr))
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ class SafeMIMEText(MIMEText):
|
||||||
This overrides the default as_string() implementation to not mangle
|
This overrides the default as_string() implementation to not mangle
|
||||||
lines that begin with 'From '. See bug #13433 for details.
|
lines that begin with 'From '. See bug #13433 for details.
|
||||||
"""
|
"""
|
||||||
fp = BytesIO()
|
fp = six.StringIO()
|
||||||
g = Generator(fp, mangle_from_ = False)
|
g = Generator(fp, mangle_from_ = False)
|
||||||
g.flatten(self, unixfrom=unixfrom)
|
g.flatten(self, unixfrom=unixfrom)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
@ -156,7 +155,7 @@ class SafeMIMEMultipart(MIMEMultipart):
|
||||||
This overrides the default as_string() implementation to not mangle
|
This overrides the default as_string() implementation to not mangle
|
||||||
lines that begin with 'From '. See bug #13433 for details.
|
lines that begin with 'From '. See bug #13433 for details.
|
||||||
"""
|
"""
|
||||||
fp = BytesIO()
|
fp = six.StringIO()
|
||||||
g = Generator(fp, mangle_from_ = False)
|
g = Generator(fp, mangle_from_ = False)
|
||||||
g.flatten(self, unixfrom=unixfrom)
|
g.flatten(self, unixfrom=unixfrom)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
@ -210,8 +209,7 @@ class EmailMessage(object):
|
||||||
|
|
||||||
def message(self):
|
def message(self):
|
||||||
encoding = self.encoding or settings.DEFAULT_CHARSET
|
encoding = self.encoding or settings.DEFAULT_CHARSET
|
||||||
msg = SafeMIMEText(smart_str(self.body, encoding),
|
msg = SafeMIMEText(self.body, self.content_subtype, encoding)
|
||||||
self.content_subtype, encoding)
|
|
||||||
msg = self._create_message(msg)
|
msg = self._create_message(msg)
|
||||||
msg['Subject'] = self.subject
|
msg['Subject'] = self.subject
|
||||||
msg['From'] = self.extra_headers.get('From', self.from_email)
|
msg['From'] = self.extra_headers.get('From', self.from_email)
|
||||||
|
@ -293,7 +291,7 @@ class EmailMessage(object):
|
||||||
basetype, subtype = mimetype.split('/', 1)
|
basetype, subtype = mimetype.split('/', 1)
|
||||||
if basetype == 'text':
|
if basetype == 'text':
|
||||||
encoding = self.encoding or settings.DEFAULT_CHARSET
|
encoding = self.encoding or settings.DEFAULT_CHARSET
|
||||||
attachment = SafeMIMEText(smart_str(content, encoding), subtype, encoding)
|
attachment = SafeMIMEText(content, subtype, encoding)
|
||||||
else:
|
else:
|
||||||
# Encode non-text attachments with base64.
|
# Encode non-text attachments with base64.
|
||||||
attachment = MIMEBase(basetype, subtype)
|
attachment = MIMEBase(basetype, subtype)
|
||||||
|
@ -313,9 +311,11 @@ class EmailMessage(object):
|
||||||
attachment = self._create_mime_attachment(content, mimetype)
|
attachment = self._create_mime_attachment(content, mimetype)
|
||||||
if filename:
|
if filename:
|
||||||
try:
|
try:
|
||||||
filename = filename.encode('ascii')
|
filename.encode('ascii')
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
filename = ('utf-8', '', filename.encode('utf-8'))
|
if not six.PY3:
|
||||||
|
filename = filename.encode('utf-8')
|
||||||
|
filename = ('utf-8', '', filename)
|
||||||
attachment.add_header('Content-Disposition', 'attachment',
|
attachment.add_header('Content-Disposition', 'attachment',
|
||||||
filename=filename)
|
filename=filename)
|
||||||
return attachment
|
return attachment
|
||||||
|
|
|
@ -8,6 +8,7 @@ import warnings
|
||||||
from django.core.management.base import BaseCommand, CommandError, handle_default_options
|
from django.core.management.base import BaseCommand, CommandError, handle_default_options
|
||||||
from django.core.management.color import color_style
|
from django.core.management.color import color_style
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
# For backwards compatibility: get_version() used to be in this module.
|
# For backwards compatibility: get_version() used to be in this module.
|
||||||
from django import get_version
|
from django import get_version
|
||||||
|
@ -228,7 +229,7 @@ class ManagementUtility(object):
|
||||||
"Available subcommands:",
|
"Available subcommands:",
|
||||||
]
|
]
|
||||||
commands_dict = collections.defaultdict(lambda: [])
|
commands_dict = collections.defaultdict(lambda: [])
|
||||||
for name, app in get_commands().iteritems():
|
for name, app in six.iteritems(get_commands()):
|
||||||
if app == 'django.core':
|
if app == 'django.core':
|
||||||
app = 'django'
|
app = 'django'
|
||||||
else:
|
else:
|
||||||
|
@ -294,7 +295,7 @@ class ManagementUtility(object):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
curr = ''
|
curr = ''
|
||||||
|
|
||||||
subcommands = get_commands().keys() + ['help']
|
subcommands = list(get_commands()) + ['help']
|
||||||
options = [('--help', None)]
|
options = [('--help', None)]
|
||||||
|
|
||||||
# subcommand
|
# subcommand
|
||||||
|
|
|
@ -6,7 +6,6 @@ be executed through ``django-admin.py`` or ``manage.py``).
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from io import BytesIO
|
|
||||||
from optparse import make_option, OptionParser
|
from optparse import make_option, OptionParser
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -14,6 +13,7 @@ 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 smart_str
|
||||||
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
|
|
||||||
class CommandError(Exception):
|
class CommandError(Exception):
|
||||||
|
@ -273,7 +273,7 @@ class BaseCommand(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from django.core.management.validation import get_validation_errors
|
from django.core.management.validation import get_validation_errors
|
||||||
s = BytesIO()
|
s = StringIO()
|
||||||
num_errors = get_validation_errors(s, app)
|
num_errors = get_validation_errors(s, app)
|
||||||
if num_errors:
|
if num_errors:
|
||||||
s.seek(0)
|
s.seek(0)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -7,7 +9,7 @@ from django.core.management.base import BaseCommand, CommandError
|
||||||
def has_bom(fn):
|
def has_bom(fn):
|
||||||
with open(fn, 'rb') as f:
|
with open(fn, 'rb') as f:
|
||||||
sample = f.read(4)
|
sample = f.read(4)
|
||||||
return sample[:3] == '\xef\xbb\xbf' or \
|
return sample[:3] == b'\xef\xbb\xbf' or \
|
||||||
sample.startswith(codecs.BOM_UTF16_LE) or \
|
sample.startswith(codecs.BOM_UTF16_LE) or \
|
||||||
sample.startswith(codecs.BOM_UTF16_BE)
|
sample.startswith(codecs.BOM_UTF16_BE)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.core.cache.backends.db import BaseDatabaseCache
|
||||||
from django.core.management.base import LabelCommand, CommandError
|
from django.core.management.base import LabelCommand, CommandError
|
||||||
from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
|
from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
|
|
||||||
class Command(LabelCommand):
|
class Command(LabelCommand):
|
||||||
|
@ -60,7 +60,7 @@ class Command(LabelCommand):
|
||||||
transaction.rollback_unless_managed(using=db)
|
transaction.rollback_unless_managed(using=db)
|
||||||
raise CommandError(
|
raise CommandError(
|
||||||
"Cache table '%s' could not be created.\nThe error was: %s." %
|
"Cache table '%s' could not be created.\nThe error was: %s." %
|
||||||
(tablename, force_unicode(e)))
|
(tablename, force_text(e)))
|
||||||
for statement in index_output:
|
for statement in index_output:
|
||||||
curs.execute(statement)
|
curs.execute(statement)
|
||||||
transaction.commit_unless_managed(using=db)
|
transaction.commit_unless_managed(using=db)
|
||||||
|
|
|
@ -22,9 +22,7 @@ class Command(NoArgsCommand):
|
||||||
default_settings = module_to_dict(global_settings)
|
default_settings = module_to_dict(global_settings)
|
||||||
|
|
||||||
output = []
|
output = []
|
||||||
keys = user_settings.keys()
|
for key in sorted(user_settings.keys()):
|
||||||
keys.sort()
|
|
||||||
for key in keys:
|
|
||||||
if key not in default_settings:
|
if key not in default_settings:
|
||||||
output.append("%s = %s ###" % (key, user_settings[key]))
|
output.append("%s = %s ###" % (key, user_settings[key]))
|
||||||
elif user_settings[key] != default_settings[key]:
|
elif user_settings[key] != default_settings[key]:
|
||||||
|
|
|
@ -7,6 +7,7 @@ from django.core.management.base import NoArgsCommand, CommandError
|
||||||
from django.core.management.color import no_style
|
from django.core.management.color import no_style
|
||||||
from django.core.management.sql import sql_flush, emit_post_sync_signal
|
from django.core.management.sql import sql_flush, emit_post_sync_signal
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
from django.utils.six.moves import input
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
class Command(NoArgsCommand):
|
||||||
|
@ -45,7 +46,7 @@ class Command(NoArgsCommand):
|
||||||
sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences)
|
sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences)
|
||||||
|
|
||||||
if interactive:
|
if interactive:
|
||||||
confirm = raw_input("""You have requested a flush of the database.
|
confirm = input("""You have requested a flush of the database.
|
||||||
This will IRREVERSIBLY DESTROY all data currently in the %r database,
|
This will IRREVERSIBLY DESTROY all data currently in the %r database,
|
||||||
and return each table to the state it was in after syncdb.
|
and return each table to the state it was in after syncdb.
|
||||||
Are you sure you want to do this?
|
Are you sure you want to do this?
|
||||||
|
|
|
@ -14,7 +14,7 @@ from django.core.management.color import no_style
|
||||||
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
|
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
|
||||||
IntegrityError, DatabaseError)
|
IntegrityError, DatabaseError)
|
||||||
from django.db.models import get_apps
|
from django.db.models import get_apps
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_text
|
||||||
from itertools import product
|
from itertools import product
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -189,7 +189,7 @@ class Command(BaseCommand):
|
||||||
'app_label': obj.object._meta.app_label,
|
'app_label': obj.object._meta.app_label,
|
||||||
'object_name': obj.object._meta.object_name,
|
'object_name': obj.object._meta.object_name,
|
||||||
'pk': obj.object.pk,
|
'pk': obj.object.pk,
|
||||||
'error_msg': force_unicode(e)
|
'error_msg': force_text(e)
|
||||||
},)
|
},)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ To add your own serializers, use the SERIALIZATION_MODULES setting::
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import importlib
|
from django.utils import importlib
|
||||||
|
from django.utils import six
|
||||||
from django.core.serializers.base import SerializerDoesNotExist
|
from django.core.serializers.base import SerializerDoesNotExist
|
||||||
|
|
||||||
# Built-in serializers
|
# Built-in serializers
|
||||||
|
@ -75,12 +76,12 @@ def get_serializer(format):
|
||||||
def get_serializer_formats():
|
def get_serializer_formats():
|
||||||
if not _serializers:
|
if not _serializers:
|
||||||
_load_serializers()
|
_load_serializers()
|
||||||
return _serializers.keys()
|
return list(_serializers)
|
||||||
|
|
||||||
def get_public_serializer_formats():
|
def get_public_serializer_formats():
|
||||||
if not _serializers:
|
if not _serializers:
|
||||||
_load_serializers()
|
_load_serializers()
|
||||||
return [k for k, v in _serializers.iteritems() if not v.Serializer.internal_use_only]
|
return [k for k, v in six.iteritems(_serializers) if not v.Serializer.internal_use_only]
|
||||||
|
|
||||||
def get_deserializer(format):
|
def get_deserializer(format):
|
||||||
if not _serializers:
|
if not _serializers:
|
||||||
|
|
|
@ -5,7 +5,7 @@ Module for abstract serializer/unserializer base classes.
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import smart_unicode
|
from django.utils.encoding import smart_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
class SerializerDoesNotExist(KeyError):
|
class SerializerDoesNotExist(KeyError):
|
||||||
|
@ -136,10 +136,12 @@ class Deserializer(object):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def next(self):
|
def __next__(self):
|
||||||
"""Iteration iterface -- return the next item in the stream"""
|
"""Iteration iterface -- return the next item in the stream"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
next = __next__ # Python 2 compatibility
|
||||||
|
|
||||||
class DeserializedObject(object):
|
class DeserializedObject(object):
|
||||||
"""
|
"""
|
||||||
A deserialized model.
|
A deserialized model.
|
||||||
|
|
|
@ -12,7 +12,7 @@ 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_str
|
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
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ from __future__ import unicode_literals
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.serializers import base
|
from django.core.serializers import base
|
||||||
from django.db import models, DEFAULT_DB_ALIAS
|
from django.db import models, DEFAULT_DB_ALIAS
|
||||||
from django.utils.encoding import smart_unicode, is_protected_type
|
from django.utils.encoding import smart_text, is_protected_type
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
class Serializer(base.Serializer):
|
class Serializer(base.Serializer):
|
||||||
"""
|
"""
|
||||||
|
@ -33,8 +34,8 @@ class Serializer(base.Serializer):
|
||||||
|
|
||||||
def get_dump_object(self, obj):
|
def get_dump_object(self, obj):
|
||||||
return {
|
return {
|
||||||
"pk": smart_unicode(obj._get_pk_val(), strings_only=True),
|
"pk": smart_text(obj._get_pk_val(), strings_only=True),
|
||||||
"model": smart_unicode(obj._meta),
|
"model": smart_text(obj._meta),
|
||||||
"fields": self._current
|
"fields": self._current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ class Serializer(base.Serializer):
|
||||||
if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
|
if self.use_natural_keys and hasattr(field.rel.to, 'natural_key'):
|
||||||
m2m_value = lambda value: value.natural_key()
|
m2m_value = lambda value: value.natural_key()
|
||||||
else:
|
else:
|
||||||
m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True)
|
m2m_value = lambda value: smart_text(value._get_pk_val(), strings_only=True)
|
||||||
self._current[field.name] = [m2m_value(related)
|
self._current[field.name] = [m2m_value(related)
|
||||||
for related in getattr(obj, field.name).iterator()]
|
for related in getattr(obj, field.name).iterator()]
|
||||||
|
|
||||||
|
@ -87,9 +88,9 @@ def Deserializer(object_list, **options):
|
||||||
m2m_data = {}
|
m2m_data = {}
|
||||||
|
|
||||||
# Handle each field
|
# Handle each field
|
||||||
for (field_name, field_value) in d["fields"].iteritems():
|
for (field_name, field_value) in six.iteritems(d["fields"]):
|
||||||
if isinstance(field_value, str):
|
if isinstance(field_value, str):
|
||||||
field_value = smart_unicode(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
|
field_value = smart_text(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True)
|
||||||
|
|
||||||
field = Model._meta.get_field(field_name)
|
field = Model._meta.get_field(field_name)
|
||||||
|
|
||||||
|
@ -97,19 +98,19 @@ def Deserializer(object_list, **options):
|
||||||
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
if field.rel and isinstance(field.rel, models.ManyToManyRel):
|
||||||
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
|
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
|
||||||
def m2m_convert(value):
|
def m2m_convert(value):
|
||||||
if hasattr(value, '__iter__'):
|
if hasattr(value, '__iter__') and not isinstance(value, six.text_type):
|
||||||
return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
|
return field.rel.to._default_manager.db_manager(db).get_by_natural_key(*value).pk
|
||||||
else:
|
else:
|
||||||
return smart_unicode(field.rel.to._meta.pk.to_python(value))
|
return smart_text(field.rel.to._meta.pk.to_python(value))
|
||||||
else:
|
else:
|
||||||
m2m_convert = lambda v: smart_unicode(field.rel.to._meta.pk.to_python(v))
|
m2m_convert = lambda v: smart_text(field.rel.to._meta.pk.to_python(v))
|
||||||
m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
|
m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
|
||||||
|
|
||||||
# Handle FK fields
|
# Handle FK fields
|
||||||
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
elif field.rel and isinstance(field.rel, models.ManyToOneRel):
|
||||||
if field_value is not None:
|
if field_value is not None:
|
||||||
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
|
if hasattr(field.rel.to._default_manager, 'get_by_natural_key'):
|
||||||
if hasattr(field_value, '__iter__'):
|
if hasattr(field_value, '__iter__') and not isinstance(field_value, six.text_type):
|
||||||
obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
|
obj = field.rel.to._default_manager.db_manager(db).get_by_natural_key(*field_value)
|
||||||
value = getattr(obj, field.rel.field_name)
|
value = getattr(obj, field.rel.field_name)
|
||||||
# If this is a natural foreign key to an object that
|
# If this is a natural foreign key to an object that
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue