1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

unicode: Fixed #4161 -- Ported oldforms internal string handling across to use

unicode. Still some breakage in admin, but that is caused by other problems.
Another contribution from Ivan Sagalaev.


git-svn-id: http://code.djangoproject.com/svn/django/branches/unicode@5090 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-04-26 13:18:54 +00:00
parent 511b2591b7
commit ee0bc3b6c8
2 changed files with 79 additions and 68 deletions

View File

@ -7,6 +7,7 @@ from django.db.models import signals
from django.utils.functional import curry from django.utils.functional import curry
from django.utils.datastructures import DotExpandedDict from django.utils.datastructures import DotExpandedDict
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.encoding import smart_str
import types import types
def add_manipulators(sender): def add_manipulators(sender):
@ -111,7 +112,7 @@ class AutomaticManipulator(oldforms.Manipulator):
if self.change: if self.change:
self.fields_added, self.fields_changed, self.fields_deleted = [], [], [] self.fields_added, self.fields_changed, self.fields_deleted = [], [], []
for f in self.opts.fields: for f in self.opts.fields:
if not f.primary_key and str(getattr(self.original_object, f.attname)) != str(getattr(new_object, f.attname)): if not f.primary_key and smart_str(getattr(self.original_object, f.attname)) != smart_str(getattr(new_object, f.attname)):
self.fields_changed.append(f.verbose_name) self.fields_changed.append(f.verbose_name)
# Save many-to-many objects. Example: Set sites for a poll. # Save many-to-many objects. Example: Set sites for a poll.
@ -211,7 +212,7 @@ class AutomaticManipulator(oldforms.Manipulator):
self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj)) self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj))
else: else:
for f in related.opts.fields: for f in related.opts.fields:
if not f.primary_key and f != related.field and str(getattr(old_rel_obj, f.attname)) != str(getattr(new_rel_obj, f.attname)): if not f.primary_key and f != related.field and smart_str(getattr(old_rel_obj, f.attname)) != smart_str(getattr(new_rel_obj, f.attname)):
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
# Save many-to-many objects. # Save many-to-many objects.

View File

@ -3,6 +3,7 @@ from django.core.exceptions import PermissionDenied
from django.utils.html import escape from django.utils.html import escape
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext, ungettext from django.utils.translation import ugettext, ungettext
from django.utils.encoding import smart_unicode, smart_str
FORM_FIELD_ID_PREFIX = 'id_' FORM_FIELD_ID_PREFIX = 'id_'
@ -166,7 +167,11 @@ class FormFieldWrapper(object):
def __str__(self): def __str__(self):
"Renders the field" "Renders the field"
return str(self.formfield.render(self.data)) return unicode(self).encode('utf-8')
def __unicode__(self):
"Renders the field"
return self.formfield.render(self.data)
def __repr__(self): def __repr__(self):
return '<FormFieldWrapper for "%s">' % self.formfield.field_name return '<FormFieldWrapper for "%s">' % self.formfield.field_name
@ -196,7 +201,10 @@ class FormFieldCollection(FormFieldWrapper):
self.formfield_dict = formfield_dict self.formfield_dict = formfield_dict
def __str__(self): def __str__(self):
return str(self.formfield_dict) return unicode(self).encode('utf-8')
def __str__(self):
return unicode(self.formfield_dict)
def __getitem__(self, template_key): def __getitem__(self, template_key):
"Look up field by template key; raise KeyError on failure" "Look up field by template key; raise KeyError on failure"
@ -294,8 +302,12 @@ class FormField(object):
Subclasses should also implement a render(data) method, which is responsible Subclasses should also implement a render(data) method, which is responsible
for rending the form field in XHTML. for rending the form field in XHTML.
""" """
def __str__(self): def __str__(self):
return self.render('') return unicode(self).encode('utf-8')
def __unicode__(self):
return self.render(u'')
def __repr__(self): def __repr__(self):
return 'FormField "%s"' % self.field_name return 'FormField "%s"' % self.field_name
@ -398,14 +410,12 @@ class TextField(FormField):
def render(self, data): def render(self, data):
if data is None: if data is None:
data = '' data = u''
maxlength = '' maxlength = u''
if self.maxlength: if self.maxlength:
maxlength = 'maxlength="%s" ' % self.maxlength maxlength = u'maxlength="%s" ' % self.maxlength
if isinstance(data, unicode): return u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
data = data.encode(settings.DEFAULT_CHARSET) (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and u' required' or '',
return '<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \
(self.input_type, self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
self.field_name, self.length, escape(data), maxlength) self.field_name, self.length, escape(data), maxlength)
def html2python(data): def html2python(data):
@ -428,10 +438,8 @@ class LargeTextField(TextField):
def render(self, data): def render(self, data):
if data is None: if data is None:
data = '' data = ''
if isinstance(data, unicode): return u'<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \
data = data.encode(settings.DEFAULT_CHARSET) (self.get_id(), self.__class__.__name__, self.is_required and u' required' or u'',
return '<textarea id="%s" class="v%s%s" name="%s" rows="%s" cols="%s">%s</textarea>' % \
(self.get_id(), self.__class__.__name__, self.is_required and ' required' or '',
self.field_name, self.rows, self.cols, escape(data)) self.field_name, self.rows, self.cols, escape(data))
class HiddenField(FormField): class HiddenField(FormField):
@ -441,7 +449,7 @@ class HiddenField(FormField):
self.validator_list = validator_list[:] self.validator_list = validator_list[:]
def render(self, data): def render(self, data):
return '<input type="hidden" id="%s" name="%s" value="%s" />' % \ return u'<input type="hidden" id="%s" name="%s" value="%s" />' % \
(self.get_id(), self.field_name, escape(data)) (self.get_id(), self.field_name, escape(data))
class CheckboxField(FormField): class CheckboxField(FormField):
@ -456,7 +464,7 @@ class CheckboxField(FormField):
checked_html = '' checked_html = ''
if data or (data is '' and self.checked_by_default): if data or (data is '' and self.checked_by_default):
checked_html = ' checked="checked"' checked_html = ' checked="checked"'
return '<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \ return u'<input type="checkbox" id="%s" class="v%s" name="%s"%s />' % \
(self.get_id(), self.__class__.__name__, (self.get_id(), self.__class__.__name__,
self.field_name, checked_html) self.field_name, checked_html)
@ -471,6 +479,7 @@ class SelectField(FormField):
def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None): def __init__(self, field_name, choices=None, size=1, is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
if choices is None: choices = [] if choices is None: choices = []
choices = [(k, smart_unicode(v)) for k, v in choices]
self.field_name = field_name self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters # choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.size, self.is_required = choices, size, is_required self.choices, self.size, self.is_required = choices, size, is_required
@ -479,21 +488,21 @@ class SelectField(FormField):
self.member_name = member_name self.member_name = member_name
def render(self, data): def render(self, data):
output = ['<select id="%s" class="v%s%s" name="%s" size="%s">' % \ output = [u'<select id="%s" class="v%s%s" name="%s" size="%s">' % \
(self.get_id(), self.__class__.__name__, (self.get_id(), self.__class__.__name__,
self.is_required and ' required' or '', self.field_name, self.size)] self.is_required and u' required' or u'', self.field_name, self.size)]
str_data = str(data) # normalize to string str_data = smart_unicode(data) # normalize to string
for value, display_name in self.choices: for value, display_name in self.choices:
selected_html = '' selected_html = u''
if str(value) == str_data: if smart_unicode(value) == str_data:
selected_html = ' selected="selected"' selected_html = u' selected="selected"'
output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name))) output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(display_name)))
output.append(' </select>') output.append(u' </select>')
return '\n'.join(output) return u'\n'.join(output)
def isValidChoice(self, data, form): def isValidChoice(self, data, form):
str_data = str(data) str_data = smart_unicode(data)
str_choices = [str(item[0]) for item in self.choices] str_choices = [smart_str(item[0]) for item in self.choices]
if str_data not in str_choices: if str_data not in str_choices:
raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data': str_data, 'choices': str_choices} raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data': str_data, 'choices': str_choices}
@ -509,6 +518,7 @@ class RadioSelectField(FormField):
def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None): def __init__(self, field_name, choices=None, ul_class='', is_required=False, validator_list=None, member_name=None):
if validator_list is None: validator_list = [] if validator_list is None: validator_list = []
if choices is None: choices = [] if choices is None: choices = []
choices = [(k, smart_unicode(v)) for k, v in choices]
self.field_name = field_name self.field_name = field_name
# choices is a list of (value, human-readable key) tuples because order matters # choices is a list of (value, human-readable key) tuples because order matters
self.choices, self.is_required = choices, is_required self.choices, self.is_required = choices, is_required
@ -520,7 +530,7 @@ class RadioSelectField(FormField):
def render(self, data): def render(self, data):
""" """
Returns a special object, RadioFieldRenderer, that is iterable *and* Returns a special object, RadioFieldRenderer, that is iterable *and*
has a default str() rendered output. has a default unicode() rendered output.
This allows for flexible use in templates. You can just use the default This allows for flexible use in templates. You can just use the default
rendering: rendering:
@ -537,36 +547,36 @@ class RadioSelectField(FormField):
class RadioFieldRenderer: class RadioFieldRenderer:
def __init__(self, datalist, ul_class): def __init__(self, datalist, ul_class):
self.datalist, self.ul_class = datalist, ul_class self.datalist, self.ul_class = datalist, ul_class
def __str__(self): def __unicode__(self):
"Default str() output for this radio field -- a <ul>" "Default unicode() output for this radio field -- a <ul>"
output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')] output = [u'<ul%s>' % (self.ul_class and u' class="%s"' % self.ul_class or u'')]
output.extend(['<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist]) output.extend([u'<li>%s %s</li>' % (d['field'], d['label']) for d in self.datalist])
output.append('</ul>') output.append(u'</ul>')
return ''.join(output) return u''.join(output)
def __iter__(self): def __iter__(self):
for d in self.datalist: for d in self.datalist:
yield d yield d
def __len__(self): def __len__(self):
return len(self.datalist) return len(self.datalist)
datalist = [] datalist = []
str_data = str(data) # normalize to string str_data = smart_unicode(data) # normalize to string
for i, (value, display_name) in enumerate(self.choices): for i, (value, display_name) in enumerate(self.choices):
selected_html = '' selected_html = ''
if str(value) == str_data: if smart_unicode(value) == str_data:
selected_html = ' checked="checked"' selected_html = u' checked="checked"'
datalist.append({ datalist.append({
'value': value, 'value': value,
'name': display_name, 'name': display_name,
'field': '<input type="radio" id="%s" name="%s" value="%s"%s/>' % \ 'field': u'<input type="radio" id="%s" name="%s" value="%s"%s/>' % \
(self.get_id() + '_' + str(i), self.field_name, value, selected_html), (self.get_id() + u'_' + unicode(i), self.field_name, value, selected_html),
'label': '<label for="%s">%s</label>' % \ 'label': u'<label for="%s">%s</label>' % \
(self.get_id() + '_' + str(i), display_name), (self.get_id() + u'_' + unicode(i), display_name),
}) })
return RadioFieldRenderer(datalist, self.ul_class) return RadioFieldRenderer(datalist, self.ul_class)
def isValidChoice(self, data, form): def isValidChoice(self, data, form):
str_data = str(data) str_data = smart_unicode(data)
str_choices = [str(item[0]) for item in self.choices] str_choices = [smart_unicode(item[0]) for item in self.choices]
if str_data not in str_choices: if str_data not in str_choices:
raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':str_data, 'choices':str_choices} raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':str_data, 'choices':str_choices}
@ -590,22 +600,22 @@ class NullBooleanField(SelectField):
class SelectMultipleField(SelectField): class SelectMultipleField(SelectField):
requires_data_list = True requires_data_list = True
def render(self, data): def render(self, data):
output = ['<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple">' % \ output = [u'<select id="%s" class="v%s%s" name="%s" size="%s" multiple="multiple">' % \
(self.get_id(), self.__class__.__name__, self.is_required and ' required' or '', (self.get_id(), self.__class__.__name__, self.is_required and u' required' or u'',
self.field_name, self.size)] self.field_name, self.size)]
str_data_list = map(str, data) # normalize to strings str_data_list = map(smart_unicode, data) # normalize to strings
for value, choice in self.choices: for value, choice in self.choices:
selected_html = '' selected_html = u''
if str(value) in str_data_list: if smart_unicode(value) in str_data_list:
selected_html = ' selected="selected"' selected_html = u' selected="selected"'
output.append(' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice))) output.append(u' <option value="%s"%s>%s</option>' % (escape(value), selected_html, escape(choice)))
output.append(' </select>') output.append(u' </select>')
return '\n'.join(output) return u'\n'.join(output)
def isValidChoice(self, field_data, all_data): def isValidChoice(self, field_data, all_data):
# data is something like ['1', '2', '3'] # data is something like ['1', '2', '3']
str_choices = [str(item[0]) for item in self.choices] str_choices = [smart_unicode(item[0]) for item in self.choices]
for val in map(str, field_data): for val in map(smart_unicode, field_data):
if val not in str_choices: if val not in str_choices:
raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':val, 'choices':str_choices} raise validators.ValidationError, ugettext("Select a valid choice; '%(data)s' is not in %(choices)s.") % {'data':val, 'choices':str_choices}
@ -642,18 +652,18 @@ class CheckboxSelectMultipleField(SelectMultipleField):
new_data.setlist(self.field_name, data_list) new_data.setlist(self.field_name, data_list)
def render(self, data): def render(self, data):
output = ['<ul%s>' % (self.ul_class and ' class="%s"' % self.ul_class or '')] output = [u'<ul%s>' % (self.ul_class and u' class="%s"' % self.ul_class or u'')]
str_data_list = map(str, data) # normalize to strings str_data_list = map(smart_unicode, data) # normalize to strings
for value, choice in self.choices: for value, choice in self.choices:
checked_html = '' checked_html = u''
if str(value) in str_data_list: if smart_unicode(value) in str_data_list:
checked_html = ' checked="checked"' checked_html = u' checked="checked"'
field_name = '%s%s' % (self.field_name, value) field_name = u'%s%s' % (self.field_name, value)
output.append('<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \ output.append(u'<li><input type="checkbox" id="%s" class="v%s" name="%s"%s value="on" /> <label for="%s">%s</label></li>' % \
(self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html, (self.get_id() + escape(value), self.__class__.__name__, field_name, checked_html,
self.get_id() + escape(value), choice)) self.get_id() + escape(value), choice))
output.append('</ul>') output.append(u'</ul>')
return '\n'.join(output) return u'\n'.join(output)
#################### ####################
# FILE UPLOADS # # FILE UPLOADS #
@ -674,7 +684,7 @@ class FileUploadField(FormField):
raise validators.CriticalValidationError, ugettext("The submitted file is empty.") raise validators.CriticalValidationError, ugettext("The submitted file is empty.")
def render(self, data): def render(self, data):
return '<input type="file" id="%s" class="v%s" name="%s" />' % \ return u'<input type="file" id="%s" class="v%s" name="%s" />' % \
(self.get_id(), self.__class__.__name__, self.field_name) (self.get_id(), self.__class__.__name__, self.field_name)
def html2python(data): def html2python(data):
@ -985,9 +995,9 @@ class CommaSeparatedIntegerField(TextField):
def render(self, data): def render(self, data):
if data is None: if data is None:
data = '' data = u''
elif isinstance(data, (list, tuple)): elif isinstance(data, (list, tuple)):
data = ','.join(data) data = u','.join(data)
return super(CommaSeparatedIntegerField, self).render(data) return super(CommaSeparatedIntegerField, self).render(data)
class RawIdAdminField(CommaSeparatedIntegerField): class RawIdAdminField(CommaSeparatedIntegerField):