Here is a way to get a drop down list from a queryset, with a list of "featured" items appearing at the top (from another queryset). This can be used for long select boxes which have a subset of commonly used values. The empty label is used as a separator and values can appear in both the featured set and the full set (it's more usable if they are in both).
For example a country drop down list with 5 featured countries might look like this:
Andorra
Australia
Kazakhstan
Singapore
Turkey
------------
Afghanistan
Albania
Algeria
American Samoa
Andorra
Angola
(hundreds more)
To use this, define your form field like this:
country = FeaturedModelChoiceField(queryset=Country.objects.all(),
featured_queryset=Country.objects.featured())
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 | from django import forms
class FeaturedModelChoiceIterator(object):
# Adapted from django.forms.models.ModelChoiceIterator
def __init__(self, field):
self.field = field
self.queryset = field.queryset
self.featured_queryset = field.featured_queryset
def __iter__(self):
# Just show all the featured content
for obj in self.featured_queryset.all():
yield self.choice(obj)
# Add the empty label between featured and non-featured content
if self.field.empty_label is not None:
yield (u"", self.field.empty_label)
# And here is the non-featured content
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):
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))
class FeaturedModelChoiceField(forms.ModelChoiceField):
""" This is just like a model choice field, but will add a set of "featured"
choices to the top of the list. These choices are provided by the
featured_queryset parameter.
"""
def __init__(self, featured_queryset, *args, **kwargs):
self.featured_queryset = featured_queryset
super(FeaturedModelChoiceField, self).__init__(*args, **kwargs)
def _get_choices(self):
# NB this method is not in the public Django API.
# 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 FeaturedModelChoiceIterator(self)
choices = property(_get_choices, forms.ChoiceField._set_choices)
def _get_featured_queryset(self):
return self._featured_queryset
def _set_featured_queryset(self, queryset):
self._featured_queryset = queryset
self.widget.choices = self.choices
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 4 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months 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
Please login first before commenting.