Настройка / удаление Django выберите поле пустой параметр
Я использую Django 1.0.2. Я написал модель, поддержанную моделью. Эта модель имеет внешний ключ, где blank=False. Когда Django генерирует HTML для этой формы, он создает поле выбора с одним параметром для каждой строки в таблице, на которую ссылается ForeignKey. Он также создает параметр в верхней части списка, который не имеет значения и отображается в виде серии тире:
<option value="">---------</option>
то, что я хотел бы знать:
- каков самый чистый способ удалить это автоматически сгенерированный параметр из поля выбора?
-
каков самый чистый способ настроить его так, чтобы он показывался как:
<option value="">Select Item</option>
В поисках решения я наткнулся билет Джанго 4653 что создало у меня впечатление, что у других был тот же вопрос и что поведение по умолчанию Django, возможно, было изменено. Этот билет старше года, поэтому я надеялся, что может быть более чистый способ выполнить их вещи.
Спасибо за любую помощь,
Джефф
Edit: я настроил поле ForeignKey как таковое:
verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)
Это устанавливает значение по умолчанию, так что это больше не пустой/тире вариант, но, к сожалению, это не кажется, чтобы решить любой из моих вопросов. То есть, опция пустой/тире по-прежнему отображается в списке.
15 ответов:
не проверял, но на основе чтения кода здесь и здесь Я считаю, что это должно работать:
class ThingForm(models.ModelForm): class Meta: model = Thing def __init__(self, *args, **kwargs): super(ThingForm, self).__init__(*args, **kwargs) self.fields['verb'].empty_label = None
EDIT: это документирована, хотя вы не обязательно знаете, чтобы искать ModelChoiceField, если вы работаете с автоматически сгенерированной ModelForm.
EDIT: как отмечает jlpp в своем ответе, это не полный - вы должны повторно назначить выбор виджетов после изменения атрибут empty_label. Поскольку это немного хаки, другой вариант, который может быть проще понять, просто переопределяет весь ModelChoiceField:
class ThingForm(models.ModelForm): verb = ModelChoiceField(Verb.objects.all(), empty_label=None) class Meta: model = Thing
документы
пустой выбор не будет включен если поле модели имеет значение blank=False и явное значение по умолчанию (значение по умолчанию значение будет выбрано изначально вместо.)
Так что установите значение по умолчанию, и вы в порядке
С ответом Карла в качестве руководства и после укоренения вокруг источника Django в течение нескольких часов я думаю, что это полное решение:
чтобы удалить пустую опцию (расширяя пример Карла):
class ThingForm(models.ModelForm): class Meta: model = Thing def __init__(self, *args, **kwargs): super(ThingForm, self).__init__(*args, **kwargs) self.fields['verb'].empty_label = None # following line needed to refresh widget copy of choice list self.fields['verb'].widget.choices = self.fields['verb'].choices
для настройки пустой метки опции по существу то же самое:
class ThingForm(models.ModelForm): class Meta: model = Thing def __init__(self, *args, **kwargs): super(ThingForm, self).__init__(*args, **kwargs) self.fields['verb'].empty_label = "Select a Verb" # following line needed to refresh widget copy of choice list self.fields['verb'].widget.choices = self.fields['verb'].choices
Я думаю, что этот подход применяется ко всем сценариям, где ModelChoiceFields отображаются как HTML, но я не уверен. Я установлено, что при инициализации этих полей их выбор передается в виджет Select (см. django.формы.поля.ChoiceField._set_choices). Установка empty_label после инициализации не обновляет список выбора виджета Select. Я недостаточно знаком с Django, чтобы знать, Следует ли это считать ошибкой.
вы можете использовать это на вашей модели:
class MyModel(models.Model): name = CharField('fieldname', max_length=10, default=None)
default=None - это ответ :D
примечание: Я пробовал это на Django 1.7
Что касается django 1.4, все, что вам нужно, это установить значение "default" и "blank=False" в поле выбора
class MyModel(models.Model): CHOICES = ( (0, 'A'), (1, 'B'), ) choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
посмотреть здесь для полного обсуждения и методов решения этого вопроса.
вы можете сделать это в админке:
formfield_overrides = { models.ForeignKey: {'empty_label': None}, }
self.fields['xxx'].empty_value = None
не будет работать, если тип поляTypedChoiceField
не естьempty_label
собственность.что мы должны сделать, это удалить первый вариант:
1 . Если вы хотите построить
BaseForm
автоопределениеTypedChoiceField
class BaseForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(BaseForm, self).__init__(*args, **kwargs) for field_name in self.fields: field = self.fields.get(field_name) if field and isinstance(field , forms.TypedChoiceField): field.choices = field.choices[1:] # code to process other Field # .... class AddClientForm(BaseForm): pass
2.только несколько форм, вы можете использовать:
class AddClientForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(AddClientForm, self).__init__(*args, **kwargs) self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
я возился с этим сегодня и просто придумал
трус hackизящные решения:# Cowardly handle ModelChoiceField empty label # we all hate that '-----' thing class ModelChoiceField_init_hack(object): @property def empty_label(self): return self._empty_label @empty_label.setter def empty_label(self, value): self._empty_label = value if value and value.startswith('-'): self._empty_label = 'Select an option' ModelChoiceField.__bases__ += (ModelChoiceField_init_hack,)
теперь вы можете настроить по умолчанию
ModelChoiceField
пустая метка на все, что вы хотите. : -)PS: нет необходимости в downvotes, безвредные патчи обезьяны всегда удобны.
для последней версии django первый ответ должен быть таким
class ThingForm(models.ModelForm): class Meta: model = Thing def __init__(self, *args, **kwargs): self.base_fields['cargo'].empty_label = None super(ThingForm, self).__init__(*args, **kwargs)`
здесь есть много отличных ответов, но я все еще не полностью удовлетворен реализацией. Я также немного разочарован тем, что выбор виджетов из разных источников (внешние ключи, варианты) дает разное поведение.
у меня есть дизайн, с которым я работаю, где выберите поля всегда есть пустой вариант, и если они требуются, они будут иметь звезду рядом с ними, и форма просто не будет проверять, если они остаются пустыми. Тем не менее, я могу только правильно переопределите empty_label для полей, которые не являются
TypedChoiceField
s.вот какой результат должны выглядеть. Первым результатом всегда является имя поля - в моем случае,
label
.вот что я в конечном итоге делает. Ниже приведен переопределенный
__init__
метод моей формы:def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for _, field in self.fields.items(): if hasattr(field, 'empty_label'): field.empty_label = field.label if isinstance(field, forms.TypedChoiceField): field.choices = [('', field.label)] + [choice for choice in field.choices if choice[0]]
начиная с Django 1.7, вы можете настроить метку для пустого значения, добавив значение в список вариантов в определении поля модели. Из документации по настройке выбор полей:
Если в поле не задано значение blank=False вместе с значением по умолчанию, то метка, содержащая "---------" будет отображаться с помощью поля выбора. Чтобы переопределить это поведение, добавьте кортеж к вариантам, содержащим None; например (None, 'Your String For Display'). Кроме того, вы можете использовать пустую строку вместо None, где это имеет смысл - например, на CharField.
Я проверил документацию для разных версий Django и обнаружил, что это был добавлено в Django 1.7.
это становится более сложным, когда выбор-это внешние ключи и если вы хотите фильтр выбор на основе некоторых критериев. В таком случае, если вы выберите
empty_label
а затем повторно назначить выбор (вы можете применить фильтрацию здесь тоже) пустая метка будет пустой:class ThingForm(models.ModelForm): class Meta: model = Thing def __init__(self, *args, **kwargs): super(ThingForm, self).__init__(*args, **kwargs) self.fields['verb'].empty_label = None self.fields['verb'].queryset=Verb.objects.all()
bbasically, первая строка под
init
может применяться для всех полей в форме с циклом или встроенным циклом:def __init__(self,user, *args, **kwargs): super(NewTicket, self).__init__(*args, **kwargs) for f in self.fields: self.fields[f].empty_label = None # or "Please Select" etc