ChoiceField не отображает пустую метку при использовании кортежа
Что я пытаюсь сделать
Я собираюсь хранить данные о конкурсах в моей базе данных. Я хочу, чтобы иметь возможность искать соревнования по определенным критериям - тип соревнований в частности.
О типах соревнований
Типы соревнований хранятся в кортеже. Немного укороченный пример:
COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)
Они используются в модели следующим образом (опять же - это сокращенная/упрощенная версия модели):
class Competition(models.Model):
name = models.CharField(max_length=256)
type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES)
Форма поиска
Я не хочу, чтобы поля были необходимы в форме поиска, поэтому форма определяется следующим образом:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
Проблема
Я хочу, чтобы виджет выбора в ChoiceField отображал пустую метку, но я ее не получаю. Любая помощь с этим будет высоко оценена:)
Ответы
Ответ 1
Я нашел решение, которое работает так, как я хочу, без нарушения принципа DRY. Не очень чистый, но я должен это сделать.
Согласно выбор документации не должен быть кортежем:
Наконец, обратите внимание, что выбор может быть любым итерируемый объект - необязательно список или кортеж. Это позволяет построить выбор динамически. Но если вы найдете вы сами выбираете варианты взлома динамичный, вам, вероятно, лучше используя соответствующую таблицу базы данных с Внешний ключ. выбор предназначен для статические данные, которые не сильно меняются, если когда-либо.
Итак, решение, на котором я собираюсь на данный момент:
COMPETITION_TYPE_CHOICES = [
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
]
COMP_TYPE_CHOICES_AND_EMPTY = [('','All')] + COMPETITION_TYPE_CHOICES
И затем:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMP_TYPE_CHOICES_AND_EMPTY, required=False)
Модель остается такой же, как и она.
Ответ 2
Я пробовал решения Monika и Evgeniy без успеха, но у Моники есть хороший момент в том, что выбор не обязательно должен быть кортежами. Поэтому самым простым (и DRYest) решением является просто сделать то, что Django уже делает в поле модели. Просто добавьте пустой выбор и кортежи вместе после преобразования их в список:
from django.db.models.fields import BLANK_CHOICE_DASH
...
type = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(COMPETITION_TYPE_CHOICES), required=False)
Ответ 3
Лучший выбор - обновить выбор полей в форме init.
COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
def __init__(self, *args, **kwargs):
super(CompetitionSearchForm, self).__init__(*args, **kwargs)
self.fields['type'].choices.insert(0, ('','---------' ) )
Ответ 4
Просто небольшое изменение Evgeniy answer, которое проверяет, не добавлена ли пустая альтернатива.
Без проверки (по крайней мере, при запуске встроенного сервера) добавляется дополнительная лишняя метка для каждой перезагрузки страницы.
COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
def __init__(self, *args, **kwargs):
super(CompetitionSearchForm, self).__init__(*args, **kwargs)
if not self.fields['type'].choices[0][0] == '':
self.fields['type'].choices.insert(0, ('','---------' ) )
Ответ 5
Согласно документации:
Можно либо итерабельный (например, список или кортеж) двухкортежей для использования в качестве вариантов для этого поля, либо вызываемый, который возвращает такой итерабельный. (https://docs.djangoproject.com/en/dev/ref/forms/fields/)
Итак, вы можете просто:
sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES)
Ответ 6
Попробуйте добавить blank=True
в поля модели (при условии, что вы хотите), затем измените форму на ModelForm и удалите определения полей. Обратите внимание, что любые поля, для которых вы устанавливаете blank=True
, не потребуются при проверке или сохранении модели. Опять же, это может быть не то, что вы хотите, но если это позволит Django автоматически позаботиться о нескольких вещах.
В противном случае просто измените свой COMPETITION_TYPE_CHOICES
на:
COMPETITION_TYPE_CHOICES = (
('', '---------'),
('1', 'Olympic Games'),
('2', 'ISU Championships'),
('3', 'Grand Prix Series'),
)
Ответ 7
Почему вы не используете ModelForm, если у вас уже есть класс модели?
Лучшее решение:
forms.py
class CompetitionSearchForm(ModelForm):
class Meta:
model = Competition
models.py
class Competition(models.Model):
name = models.CharField(max_length=256)
type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES, default=COMPETITION_TYPE_CHOICES[0][0], blank=True)
Вы можете установить blank = False, чтобы удалить пустую_клавишу из списка