Настройка / удаление Django выберите поле пустой параметр


Я использую Django 1.0.2. Я написал модель, поддержанную моделью. Эта модель имеет внешний ключ, где blank=False. Когда Django генерирует HTML для этой формы, он создает поле выбора с одним параметром для каждой строки в таблице, на которую ссылается ForeignKey. Он также создает параметр в верхней части списка, который не имеет значения и отображается в виде серии тире:

<option value="">---------</option>

то, что я хотел бы знать:

  1. каков самый чистый способ удалить это автоматически сгенерированный параметр из поля выбора?
  2. каков самый чистый способ настроить его так, чтобы он показывался как:

    <option value="">Select Item</option>
    

В поисках решения я наткнулся билет Джанго 4653 что создало у меня впечатление, что у других был тот же вопрос и что поведение по умолчанию Django, возможно, было изменено. Этот билет старше года, поэтому я надеялся, что может быть более чистый способ выполнить их вещи.

Спасибо за любую помощь,

Джефф

Edit: я настроил поле ForeignKey как таковое:

verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)

Это устанавливает значение по умолчанию, так что это больше не пустой/тире вариант, но, к сожалению, это не кажется, чтобы решить любой из моих вопросов. То есть, опция пустой/тире по-прежнему отображается в списке.

15 68

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 в течение нескольких часов я думаю, что это полное решение:

  1. чтобы удалить пустую опцию (расширяя пример Карла):

    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
    
  2. для настройки пустой метки опции по существу то же самое:

    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)`

на

Я нахожу решение!!

но не для ForeignKey : -)

здесь есть много отличных ответов, но я все еще не полностью удовлетворен реализацией. Я также немного разочарован тем, что выбор виджетов из разных источников (внешние ключи, варианты) дает разное поведение.

у меня есть дизайн, с которым я работаю, где выберите поля всегда есть пустой вариант, и если они требуются, они будут иметь звезду рядом с ними, и форма просто не будет проверять, если они остаются пустыми. Тем не менее, я могу только правильно переопределите empty_label для полей, которые не являются TypedChoiceFields.

вот какой результат должны выглядеть. Первым результатом всегда является имя поля - в моем случае,label.

select widget

вот что я в конечном итоге делает. Ниже приведен переопределенный __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