ModelChoiceTitleField is a ModelChoiceField descendent that creates <OPTIONS> with title elements based on the field specified in title_source_field:
priority=ModelChoiceTitleField(Priority.objects.all(),
initial=Priority.objects.get(default=True).id,
title_source_field='long_description')
That will generate a <SELECT>
element looking like:
<select name="priority" id="id_priority">
<option value="1" title="Some extremely important task.">Emergency</option>
...
</select>
In the <option>
above, the title was retrieved from the long_description
field for the instance of the Priority class. The word Emergency came from a call to the instance of the Priority class' __unicode__()
method. The value of the option is the PK for the instance of the Priority class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #
# Example of usage in a form:
#
#priority=ModelChoiceTitleField(Priority.objects.all(),
# initial=Priority.objects.get(default=True).id,
# title_source_field='long_description')
#
class SelectWithTitle(Select):
'''
An overriden select widget to be used with ModelChoiceTitleField
'''
def render_options(self, choices, selected_choices):
def render_option(option_value, option_label, option_title):
option_value = force_unicode(option_value)
selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
return u'<option value="%s"%s title="%s">%s</option>' % (
escape(option_value), selected_html, option_title,
conditional_escape(force_unicode(option_label)))
# Normalize to strings.
selected_choices = set([force_unicode(v) for v in selected_choices])
output = []
for option_value, option_label, option_title in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
for option in option_label:
output.append(render_option(*option))
output.append(u'</optgroup>')
else:
output.append(render_option(option_value, option_label, option_title))
return u'\n'.join(output)
class ModelChoiceTitleIterator(ModelChoiceIterator):
'''
A ModelChoiceIterator that includes the label for the options
'''
def __iter__(self):
if self.field.empty_label is not None:
yield (u"", self.field.empty_label, "")
if self.field.cache_choices:
if self.field.choice_cache is None:
self.field.choice_cache = [
self.choice(obj) for obj in self.queryset.all()
]
for choice in self.field.choice_cache:
yield choice
else:
for obj in self.queryset.all():
yield self.choice(obj)
def choice(self, obj):
'''
obj is each queryset object instance (i.e. each row from the DB)
'''
if self.field.to_field_name:
key = obj.serializable_value(self.field.to_field_name)
else:
key = obj.pk
return (key, self.field.label_from_instance(obj), obj.__dict__[self.field.title_source_field])
class ModelChoiceTitleField(ModelChoiceField):
"""
A ModelChoiceField that also provides an iterator with labels for options
title_source_field - the field name that will be used to retrieve the title for the element
"""
widget=SelectWithTitle
def __init__(self, queryset, empty_label=u"---------", cache_choices=False,
required=True, widget=None, label=None, initial=None,
help_text=None, to_field_name=None, title_source_field=None, *args, **kwargs):
super(ModelChoiceTitleField, self).__init__(queryset, empty_label,
cache_choices, required, widget, label, initial, help_text,
*args, **kwargs)
self.title_source_field = title_source_field
def _get_choices(self):
# If self._choices is set, then somebody must have manually set
# the property self.choices. In this case, just return self._choices.
if hasattr(self, '_choices'):
return self._choices
# Otherwise, execute the QuerySet in self.queryset to determine the
# choices dynamically. Return a fresh QuerySetIterator that has not been
# consumed. Note that we're instantiating a new QuerySetIterator *each*
# time _get_choices() is called (and, thus, each time self.choices is
# accessed) so that we can ensure the QuerySet has not been consumed. This
# construct might look complicated but it allows for lazy evaluation of
# the queryset.
return ModelChoiceTitleIterator(self)
choices = property(_get_choices, ChoiceField._set_choices)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Awesome, thanks :P
#
Please login first before commenting.