Merge branch 'master' into schema-alteration

This commit is contained in:
Andrew Godwin 2012-08-10 12:40:37 +01:00
commit 184cf9ab79
262 changed files with 2533 additions and 1757 deletions

View File

@ -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__())

View File

@ -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'

View File

@ -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

View File

@ -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'),
) )

View File

@ -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}

View File

@ -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({

View File

@ -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):
""" """

View File

@ -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:

View File

@ -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):

View File

@ -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.

View File

@ -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('&nbsp;') result_repr = mark_safe('&nbsp;')
# 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):

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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():

View File

@ -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 = {

View File

@ -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):

View File

@ -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

View File

@ -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, '')

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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"],

View File

@ -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

View File

@ -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,
) )

View File

@ -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

View File

@ -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

View File

@ -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."

View File

@ -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):

View File

@ -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,

View File

@ -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})

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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}

View File

@ -163,6 +163,8 @@ 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
@ -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):
""" """

View File

@ -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.

View File

@ -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):

View File

@ -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']

View File

@ -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

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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))

View File

@ -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])

View File

@ -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):

View File

@ -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])

View File

@ -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'])

View File

@ -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:

View File

@ -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'])

View File

@ -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)

View File

@ -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):
""" """

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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))

View File

@ -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))

View File

@ -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"]))

View File

@ -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:

View File

@ -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):

View File

@ -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 {}

View File

@ -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

View File

@ -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 = []

View File

@ -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

View File

@ -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))

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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))

View File

@ -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() }

View File

@ -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):

View File

@ -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)

View File

@ -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:

View File

@ -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.

View File

@ -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):

View File

@ -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', ''))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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]:

View File

@ -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?

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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