Можно ли создать именованные группы выбора в виджете Django select (раскрывающийся список), когда этот виджет находится в форме, которая автоматически генерируется из модели данных? Могу ли я создать виджет на левом изображении ниже?
Мой первый эксперимент по созданию формы с именованными группами был проведен вручную , вот так:
class GroupMenuOrderForm(forms.Form):
food_list = [(1, 'burger'), (2, 'pizza'), (3, 'taco'),]
drink_list = [(4, 'coke'), (5, 'pepsi'), (6, 'root beer'),]
item_list = ( ('food', tuple(food_list)), ('drinks', tuple(drink_list)),)
itemsField = forms.ChoiceField(choices = tuple(item_list))
def GroupMenuOrder(request):
theForm = GroupMenuOrderForm()
return render_to_response(menu_template, {'form': theForm,})
# generates the widget in left-side picture
И он отлично сработал, создав выпадающий виджет слева с именованными группами.
Затем я создал модель данных, которая имела в основном ту же структуру, и использовал способность Django автоматически создавать формы из моделей. Это сработало - в том смысле, что показало все варианты. Но вариантов не было в названных группах, и пока я не понял, как это сделать - если это вообще возможно.
Я нашел несколько вопросов, на которые был дан ответ: «создайте конструктор формы и выполните никакой специальной обработки там ». Но вроде как формы. ChoiceField требует кортеж для именованных групп, и я не уверен, как преобразовать кортеж в QuerySet (что, вероятно, в любом случае невозможно, если я правильно понимаю QuerySets как указатель на данные, а не фактический data).
Код, который я использовал для модели данных:
class ItemDesc(models.Model):
''' one of "food", "drink", where ID of “food” = 1, “drink” = 2 '''
desc = models.CharField(max_length=10, unique=True)
def __unicode__(self):
return self.desc
class MenuItem(models.Model):
''' one of ("burger", 1), ("pizza", 1), ("taco", 1),
("coke", 2), ("pepsi", 2), ("root beer", 2) '''
name = models.CharField(max_length=50, unique=True)
itemDesc = models.ForeignKey(ItemDesc)
def __unicode__(self):
return self.name
class PatronOrder(models.Model):
itemWanted = models.ForeignKey(MenuItem)
class ListMenuOrderForm(forms.ModelForm):
class Meta:
model = PatronOrder
def ListMenuOrder(request):
theForm = ListMenuOrderForm()
return render_to_response(menu_template, {'form': theForm,})
# generates the widget in right-side picture
Я изменю модель данных, если потребуется, но это выглядело как простая структура. Может быть, слишком много ForeignKeys? Свернуть данные и принять денормализацию? :) Или есть способ преобразовать кортеж в QuerySet или что-то , приемлемое для ModelChoiceField?
Обновление: окончательный код, основанный на meshantz ' ответ :
class FooIterator(forms.models.ModelChoiceIterator):
def __init__(self, *args, **kwargs):
super(forms.models.ModelChoiceIterator, self).__init__(*args, **kwargs)
def __iter__(self):
yield ('food', [(1L, u'burger'), (2L, u'pizza')])
yield ('drinks', [(3L, u'coke'), (4L, u'pepsi')])
class ListMenuOrderForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ListMenuOrderForm, self).__init__(*args, **kwargs)
self.fields['itemWanted'].choices = FooIterator()
class Meta:
model = PatronOrder
(Конечно, реальный код, мне нужно что-нибудь вытащить данные элемента из базы данных . )
Самым большим изменением по сравнению с djangosnippet, с которым он связан, по-видимому, является то, что Django включил часть кода, что позволяет напрямую назначать Iterator для вариантов выбора , вместо того, чтобы переопределять весь класс . Что очень приятно.