Fixed #10645 -- Added some robustness around some admin and modelform params.

Fieldset dictionary names, search fields and unique_together attribute
names all have to be convertible to strings (that has always been true).
If somebody passes in a unicode object, Python barfs because Django uses
those values as keyword argument names and function calls require
parameter names to be str objects. We now convert thing to strs
automatically.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10510 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2009-04-11 07:41:59 +00:00
parent d2fc8ae0e3
commit 3bd384aa62
5 changed files with 27 additions and 5 deletions

View File

@ -17,7 +17,7 @@ checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False)
class AdminForm(object): class AdminForm(object):
def __init__(self, form, fieldsets, prepopulated_fields): def __init__(self, form, fieldsets, prepopulated_fields):
self.form, self.fieldsets = form, fieldsets self.form, self.fieldsets = form, normalize_fieldsets(fieldsets)
self.prepopulated_fields = [{ self.prepopulated_fields = [{
'field': form[field_name], 'field': form[field_name],
'dependencies': [form[f] for f in dependencies] 'dependencies': [form[f] for f in dependencies]
@ -196,3 +196,25 @@ class AdminErrorList(forms.util.ErrorList):
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(errors_in_inline_form.values())
def normalize_fieldsets(fieldsets):
"""
Make sure the keys in fieldset dictionaries are strings. Returns the
normalized data.
"""
result = []
for name, options in fieldsets:
result.append((name, normalize_dictionary(options)))
return result
def normalize_dictionary(data_dict):
"""
Converts all the keys in "data_dict" to strings. The keys must be
convertible using str().
"""
for key, value in data_dict.items():
if not isinstance(key, str):
del data_dict[key]
data_dict[str(key)] = value
return data_dict

View File

@ -228,7 +228,7 @@ class ChangeList(object):
if self.search_fields and self.query: if self.search_fields and self.query:
for bit in self.query.split(): for bit in self.query.split():
or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.search_fields] or_queries = [models.Q(**{construct_search(str(field_name)): bit}) for field_name in self.search_fields]
other_qs = QuerySet(self.model) other_qs = QuerySet(self.model)
other_qs.dup_select_related(qs) other_qs.dup_select_related(qs)
other_qs = other_qs.filter(reduce(operator.or_, or_queries)) other_qs = other_qs.filter(reduce(operator.or_, or_queries))

View File

@ -276,7 +276,7 @@ class BaseModelForm(BaseForm):
# using it in a lookup. # using it in a lookup.
if isinstance(self.fields[field_name], ModelChoiceField): if isinstance(self.fields[field_name], ModelChoiceField):
lookup_value = lookup_value.pk lookup_value = lookup_value.pk
lookup_kwargs[field_name] = lookup_value lookup_kwargs[str(field_name)] = lookup_value
qs = self.instance.__class__._default_manager.filter(**lookup_kwargs) qs = self.instance.__class__._default_manager.filter(**lookup_kwargs)

View File

@ -169,7 +169,7 @@ class PersonAdmin(admin.ModelAdmin):
list_display = ('name', 'gender', 'alive') list_display = ('name', 'gender', 'alive')
list_editable = ('gender', 'alive') list_editable = ('gender', 'alive')
list_filter = ('gender',) list_filter = ('gender',)
search_fields = ('name',) search_fields = (u'name',)
ordering = ["id"] ordering = ["id"]
class Persona(models.Model): class Persona(models.Model):

View File

@ -11,7 +11,7 @@ class Triple(models.Model):
return u"%d, %d, %d" % (self.left, self.middle, self.right) return u"%d, %d, %d" % (self.left, self.middle, self.right)
class Meta: class Meta:
unique_together = (('left', 'middle'), ('middle', 'right')) unique_together = (('left', 'middle'), (u'middle', u'right'))
class FilePathModel(models.Model): class FilePathModel(models.Model):
path = models.FilePathField(path=os.path.dirname(__file__), match=".*\.py$", blank=True) path = models.FilePathField(path=os.path.dirname(__file__), match=".*\.py$", blank=True)