Last active
April 17, 2023 20:05
-
-
Save 1player/0cab02b415cfe3b56f1f to your computer and use it in GitHub Desktop.
Django natural sorted ModelChoiceField
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Tested with Django 1.7.1 | |
# and natsort 3.5.1 | |
# Very hackish, but that's the easiest and fastest solution I've found. | |
import natsort | |
from django import forms | |
# Adapted from private forms.ModelChoiceIterator | |
class NatSortedModelChoiceIterator(object): | |
def __init__(self, field): | |
self.field = field | |
self.queryset = field.queryset | |
def _get_choices(self): | |
if self.field.empty_label is not None: | |
yield ("", 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 __iter__(self): | |
choices = list(self._get_choices()) | |
# choices is a list of choice tuples, index 1 is the label | |
for choice in natsort.natsorted(choices, key=lambda model: model[1]): | |
yield choice | |
def __len__(self): | |
return (len(self.queryset) + | |
(1 if self.field.empty_label is not None else 0)) | |
def choice(self, obj): | |
return (self.field.prepare_value(obj), self.field.label_from_instance(obj)) | |
class NatSortedModelChoiceField(forms.ModelChoiceField): | |
def _get_choices(self): | |
if hasattr(self, '_choices'): | |
return self._choices | |
return NatSortedModelChoiceIterator(self) | |
choices = property(_get_choices, forms.ChoiceField._set_choices) | |
class NatSortedModelMultipleChoiceField(forms.ModelMultipleChoiceField, NatSortedModelChoiceField): | |
def __init__(self, *args, **kwargs): | |
NatSortedModelChoiceField.__init__(self, *args, **kwargs) | |
# Example | |
class MyForm(forms.Form): | |
field = NatSortedModelChoiceField(queryset=MyModel.objects.all()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment