Przypuśćmy, że nasza aplikacja pozwala kupić koszulkę. Dostępne kolory zależą od rozmiaru i trzeba pozwolić je jakoś wybrać. Dwa selecty? Będzie się dało wybrać nieistniejącą kombinację. Łączony select? Nieczytelnie, chyba że…
Poniższe rozwiązanie używa klasy GroupedSelect pochodzącej z Django Snippets.
from django.forms import ModelChoiceField, ValidationError from django.forms.util import smart_unicode from django.utils.itercompat import groupby from operator import attrgetter class GroupedModelChoiceIterator(object): def __init__(self, field, grouper): self.field = field self.queryset = field.queryset self.grouper = grouper def __iter__(self): if self.field.empty_label is not None: yield (None, ((u'', self.field.empty_label), )) for grouper, items in groupby(self.queryset.all(), attrgetter(self.grouper)): yield (unicode(grouper), tuple((o.pk, unicode(o)) for o in items)) class GroupedModelChoiceField(ModelChoiceField): def __init__(self, field, widget = GroupedSelect, *args, **kwargs): self._field = field super(GroupedModelChoiceField, self).__init__(widget = widget, *args, **kwargs) def _get_choices(self): return GroupedModelChoiceIterator(self, self._field) choices = property(_get_choices, None) def clean(self, value): """ Validates that the input is in self.choices. """ if value in (None, ''): value = u'' value = smart_unicode(value) valid_values = [] for group_label, group in self.choices: valid_values += [str(k) for k, v in group] if value not in valid_values: raise ValidationError(u'Select a valid choice. That choice is not one of the available choices.') return super(GroupedModelChoiceField, self).clean(value)
Przykład (zakładając, że color jest referencją na obiekt, który posiada pole size):
class SizeAndColorForm(forms.ModelForm): class Meta: model = Product fields = ['color'] color = GroupedModelChoiceField(field = 'size', label = u'size/color')


by tamok
22 kwi 2009 at 12:55
Ciekawe, ale efekt końcowy — przynajmniej w przykładzie niezbyt czytelny w praktyce, bo nie widać, co zostało wybrane (jaki rozmiar). No i przy większej ilości opcji zrobi się bałagan.
Bardziej elegancko byłoby coś mieszanego (niekoniecznie dwa selecty) w tym stylu (radio — drodown): http://tinyurl.com/c43t9a gdzie po wybraniu rozmiaru ujawniałby się dropdown z jemu przynależnymi kolorami (ale to już chyba bardziej ajaksowe rozwiązanie)
by Patrys
22 kwi 2009 at 13:00
tamok:
Mylisz AJAX z JavaScriptem. JS nie powinien być wymagany do działania aplikacji.
by riddle
22 kwi 2009 at 15:07
No i teraz to Twoje rozwiązanie najlepiej w JS rozdzielić na radiobutton (względnie coś selectable) i select. Bądź zbudować jeszcze inny interfejs, a wszystko wysyłać przez Twój formularz.
Progressive enhancement FTW.
by tamok
22 kwi 2009 at 15:13
Oczywiście ferszteje, chodziło mi o to, że to takie ajaksowe zadziałanie byłoby. „Wyberam opcję i na stronie pojawiają mi się schowane elementy bez potrzeby odświeżania”. Bez JS się nie da.
Dlatego twoja metoda jest jedyną dobrą, tyle, że znika (z oczu) rozmiar po wybraniu koloru, ewentualnie w praktyce potrzebny byłby jakiś def, który uzupełniałby nazwy kolorów w stylu „niebieski(XXL).
Bo jak rozmiarów i kolorów zrobi się więcej to potencjalna klientka-dziunia już cała głupia będzie jakiego wypasionego szerta wybrała dla swojego fakola…