Skip to content

Instantly share code, notes, and snippets.

@ojii
Created October 11, 2010 09:09
Show Gist options
  • Save ojii/620248 to your computer and use it in GitHub Desktop.
Save ojii/620248 to your computer and use it in GitHub Desktop.
from django.forms.fields import ChoiceField
from django.forms.models import ModelChoiceField, ModelMultipleChoiceField
class CachedModelChoiceIterator(object):
def __init__(self, field):
self.field = field
self.queryset = field.queryset
self.model = field.queryset.model
def __iter__(self):
if self.field.empty_label is not None:
yield (u"", self.field.empty_label)
if self.model not in CachedModelChoiceField.__cache__:
CachedModelChoiceField.__cache__[self.model] = [
self.choice(obj) for obj in self.queryset.all()
]
for choice in CachedModelChoiceField.__cache__[self.model]:
yield choice
def __len__(self):
return len(self.queryset)
def choice(self, obj):
return (self.field.prepare_value(obj), self.field.label_from_instance(obj))
class CachedModelChoiceField(ModelChoiceField):
__cache__ = {}
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 ModelChoiceIterator that has not been
# consumed. Note that we're instantiating a new ModelChoiceIterator *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 CachedModelChoiceIterator(self)
choices = property(_get_choices, ChoiceField._set_choices)
class CachedModelMultipleChoiceField(CachedModelChoiceField , ModelMultipleChoiceField): pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment