1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

unicode: Fixed a number of problems where lazily translated objects were not

being converted back to unicode strings correctly. Fixed #4359 and #4361.


git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5320 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-05-23 03:46:57 +00:00
parent d72f630fdb
commit b25f6e9526
8 changed files with 84 additions and 29 deletions

View File

@ -78,7 +78,7 @@ def result_headers(cl):
# attribute "short_description". If that doesn't exist, fall back
# to the method name. And __str__ and __unicode__ are special-cases.
if field_name == '__unicode__':
header = smart_unicode(lookup_opts.verbose_name)
header = force_unicode(lookup_opts.verbose_name)
elif field_name == '__str__':
header = smart_str(lookup_opts.verbose_name)
else:

View File

@ -12,7 +12,7 @@ from django.db.models.query import handle_legacy_orderlist, QuerySet
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.utils.html import escape
from django.utils.text import capfirst, get_text_list
from django.utils.encoding import smart_unicode, smart_str
from django.utils.encoding import force_unicode, smart_str
from django.utils.translation import ugettext as _
import operator
@ -127,11 +127,11 @@ class AdminBoundField(object):
if max([bool(f.errors()) for f in self.form_fields]):
classes.append('error')
if classes:
self.cell_class_attribute = ' class="%s" ' % ' '.join(classes)
self.cell_class_attribute = u' class="%s" ' % ' '.join(classes)
self._repr_filled = False
if field.rel:
self.related_url = '../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
self.related_url = u'../../../%s/%s/' % (field.rel.to._meta.app_label, field.rel.to._meta.object_name.lower())
def original_value(self):
if self.original:
@ -144,7 +144,7 @@ class AdminBoundField(object):
if isinstance(self.field.rel, models.ManyToOneRel):
self._display = getattr(self.original, self.field.name)
elif isinstance(self.field.rel, models.ManyToManyRel):
self._display = u", ".join([smart_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
self._display = u", ".join([force_unicode(obj) for obj in getattr(self.original, self.field.name).all()])
return self._display
def __repr__(self):
@ -255,7 +255,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if not errors:
new_object = manipulator.save(new_data)
pk_value = new_object._get_pk_val()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), ADDITION)
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), ADDITION)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
# Here, we distinguish between different save types by checking for
# the presence of keys in request.POST.
@ -268,7 +268,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po
if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable.
pk_value = '"%s"' % pk_value.replace('"', '\\"')
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, %s, "%s");</script>' % \
(pk_value, smart_unicode(new_object).replace('"', '\\"')))
(pk_value, force_unicode(new_object).replace('"', '\\"')))
elif "_addanother" in request.POST:
request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect(request.path)
@ -342,7 +342,7 @@ def change_stage(request, app_label, model_name, object_id):
change_message = ' '.join(change_message)
if not change_message:
change_message = _('No fields changed.')
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, smart_unicode(new_object), CHANGE, change_message)
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, force_unicode(new_object), CHANGE, change_message)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
if "_continue" in request.POST:
@ -431,10 +431,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), sub_obj), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(),
sub_obj._get_pk_val(), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
@ -445,10 +445,10 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
if related.field.rel.edit_inline or not related.opts.admin:
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh(deleted_objects, current_depth, ['%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []])
nh(deleted_objects, current_depth, [u'%s: %s' % (capfirst(related.opts.verbose_name), escape(sub_obj)), []])
else:
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
# If there were related objects, and the user doesn't have
@ -481,12 +481,12 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
# Display a link to the admin page.
nh(deleted_objects, current_depth, [
(_('One or more %(fieldname)s in %(name)s:') % {'fieldname': related.field.verbose_name, 'name':related.opts.verbose_name}) + \
(' <a href="../../../../%s/%s/%s/">%s</a>' % \
(u' <a href="../../../../%s/%s/%s/">%s</a>' % \
(related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []])
# If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed.
if related.opts.admin and has_related_objs:
p = '%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
if not user.has_perm(p):
perms_needed.add(related.opts.verbose_name)
@ -503,14 +503,14 @@ def delete_stage(request, app_label, model_name, object_id):
# Populate deleted_objects, a data structure of all related objects that
# will also be deleted.
deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []]
deleted_objects = [u'%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, escape(obj)), []]
perms_needed = sets.Set()
_get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1)
if request.POST: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied
obj_display = smart_unicode(obj)
obj_display = force_unicode(obj)
obj.delete()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, object_id, obj_display, DELETION)
request.user.message_set.create(message=_('The %(name)s "%(obj)s" was deleted successfully.') % {'name': opts.verbose_name, 'obj': obj_display})
@ -600,7 +600,7 @@ class ChangeList(object):
del p[k]
elif v is not None:
p[k] = v
return '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
return '?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20')
def get_results(self, request):
paginator = ObjectPaginator(self.query_set, self.lookup_opts.admin.list_per_page)

View File

@ -3,7 +3,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.db import backend, connection, models
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy, ugettext as _
from django.utils.translation import ugettext_lazy as _
import datetime
import urllib
@ -281,7 +281,7 @@ class AnonymousUser(object):
pass
def __unicode__(self):
return ugettext_lazy('AnonymousUser')
return _('AnonymousUser')
def __eq__(self, other):
return isinstance(other, self.__class__)

View File

@ -12,7 +12,7 @@ from django.db.models.loading import register_models, get_model
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
from django.utils.functional import curry
from django.utils.encoding import smart_str
from django.utils.encoding import smart_str, force_unicode
from django.conf import settings
from itertools import izip
import types
@ -88,7 +88,7 @@ class Model(object):
def __str__(self):
if hasattr(self, '__unicode__'):
return unicode(self).encode('utf-8')
return force_unicode(self).encode('utf-8')
return '%s object' % self.__class__.__name__
def __eq__(self, other):
@ -320,7 +320,7 @@ class Model(object):
def _get_FIELD_display(self, field):
value = getattr(self, field.attname)
return dict(field.choices).get(value, value)
return force_unicode(dict(field.choices).get(value, value))
def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
op = is_next and '>' or '<'

View File

@ -215,7 +215,7 @@ class AdminOptions(object):
save_on_top=False, list_select_related=False, manager=None, list_per_page=100):
self.fields = fields
self.js = js or []
self.list_display = list_display or ['__str__']
self.list_display = list_display or ['__unicode__']
self.list_display_links = list_display_links or []
self.list_filter = list_filter or []
self.date_hierarchy = date_hierarchy

View File

@ -58,9 +58,9 @@ import re
from inspect import getargspec
from django.conf import settings
from django.template.context import Context, RequestContext, ContextPopException
from django.utils.functional import curry
from django.utils.functional import curry, Promise
from django.utils.text import smart_split
from django.utils.encoding import smart_unicode, smart_str
from django.utils.encoding import smart_unicode, smart_str, force_unicode
from django.utils.translation import ugettext as _
__all__ = ('Template', 'Context', 'RequestContext', 'compile_string')
@ -705,6 +705,8 @@ def resolve_variable(path, context):
else:
raise
del bits[0]
if isinstance(current, (basestring, Promise)):
current = force_unicode(current)
return current
class Node(object):

View File

@ -33,7 +33,7 @@ __test__ = {'API_TESTS':"""
>>> s.gender
'F'
>>> a.get_gender_display()
'Male'
u'Male'
>>> s.get_gender_display()
'Female'
u'Female'
"""}

View File

@ -123,6 +123,9 @@ class ListFilterBadOne(models.Model):
class Admin:
list_filter = 'first_name'
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", if given, must be set to a list or tuple.
"""
@ -140,6 +143,9 @@ class ListFilterBadTwo(models.Model):
class Admin:
list_filter = ['first_name','last_name','full_name']
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'last_name', which isn't a field.
invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name', which isn't a field.
"""
@ -152,6 +158,9 @@ class DateHierarchyBadOne(models.Model):
class Admin:
date_hierarchy = 'first_name'
def __unicode__(self):
return self.first_name
# TODO: Date Hierarchy needs to check if field is a date/datetime field.
#model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field.
#"""
@ -164,6 +173,9 @@ class DateHierarchyBadTwo(models.Model):
class Admin:
date_hierarchy = 'nonexistent'
def __unicode__(self):
return self.first_name
model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierarchy" refers to 'nonexistent', which isn't a field.
"""
@ -175,6 +187,9 @@ class DateHierarchyGood(models.Model):
class Admin:
date_hierarchy = 'birth_day'
def __unicode__(self):
return self.first_name
class SearchFieldsBadOne(models.Model):
"Test search_fields, must be a list or tuple."
first_name = models.CharField(maxlength=30)
@ -182,6 +197,9 @@ class SearchFieldsBadOne(models.Model):
class Admin:
search_fields = ('nonexistent')
def __unicode__(self):
return self.first_name
# TODO: Add search_fields validation
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple.
#"""
@ -197,6 +215,9 @@ class SearchFieldsBadTwo(models.Model):
class Admin:
search_fields = ['first_name','last_name']
def __unicode__(self):
return self.first_name
# TODO: Add search_fields validation
#model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field.
#"""
@ -209,6 +230,8 @@ class SearchFieldsGood(models.Model):
class Admin:
search_fields = ['first_name','last_name']
def __unicode__(self):
return self.first_name
class JsBadOne(models.Model):
"Test js, must be a list or tuple"
@ -217,6 +240,9 @@ class JsBadOne(models.Model):
class Admin:
js = 'test.js'
def __unicode__(self):
return self.name
# TODO: Add a js validator
#model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple.
#"""
@ -228,6 +254,9 @@ class SaveAsBad(models.Model):
class Admin:
save_as = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a save_as validator.
#model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False.
#"""
@ -239,6 +268,9 @@ class SaveOnTopBad(models.Model):
class Admin:
save_on_top = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a save_on_top validator.
#model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False.
#"""
@ -250,6 +282,9 @@ class ListSelectRelatedBad(models.Model):
class Admin:
list_select_related = 'not True or False'
def __unicode__(self):
return self.name
# TODO: Add a list_select_related validator.
#model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False.
#"""
@ -261,6 +296,9 @@ class ListPerPageBad(models.Model):
class Admin:
list_per_page = 89.3
def __unicode__(self):
return self.name
# TODO: Add a list_per_page validator.
#model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer.
#"""
@ -273,6 +311,9 @@ class FieldsBadOne(models.Model):
class Admin:
fields = 'not a tuple'
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple.
#"""
@ -285,6 +326,9 @@ class FieldsBadTwo(models.Model):
class Admin:
fields = ('Name', {'description': 'this fieldset needs fields'})
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict.
#"""
@ -297,6 +341,9 @@ class FieldsBadThree(models.Model):
class Admin:
fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'})
def __unicode__(self):
return self.first_name
# TODO: Add a fields validator.
#model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'.
#"""
@ -313,6 +360,9 @@ class FieldsGood(models.Model):
(None, {'fields': ('birth_day',),'description': 'enter your b-day'})
)
def __unicode__(self):
return self.first_name
class OrderingBad(models.Model):
"Test ordering, must be a field."
first_name = models.CharField(maxlength=30)
@ -321,6 +371,9 @@ class OrderingBad(models.Model):
class Admin:
ordering = 'nonexistent'
def __unicode__(self):
return self.first_name
# TODO: Add a ordering validator.
#model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field.
#"""