Personalize / remova Django opção em branco caixa de seleção

votos
67

Eu estou usando Django 1.0.2. Eu escrevi um ModelForm apoiado por uma modelo. Este modelo tem uma ForeignKey onde blank = False. Quando Django gera HTML para esta forma cria-se uma caixa de seleção com uma opção para cada linha na tabela referenciada pela ForeignKey. Ele também cria uma opção no topo da lista que não tem nenhum valor e mostra como uma série de traços:

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

O que eu gostaria de saber é:

  1. Qual é a maneira mais limpa para remover esta opção auto-gerada a partir da caixa de seleção?
  2. Qual é a maneira mais limpa para personalizá-lo para que ele mostra como:

    <option value=>Select Item</option>
    

Em busca de uma solução me deparei com Django bilhete de 4653 que me deu a impressão de que os outros tinham a mesma pergunta e que o comportamento padrão do Django podem ter sido modificados. Este bilhete é mais de um ano de idade, então eu estava esperando que pode haver uma maneira mais limpa para realizar essas coisas.

Obrigado por qualquer ajuda,

Jeff

Edit: Eu configurei o campo ForeignKey como tal:

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

Isso definir o padrão para que ele não é mais a opção vazia / traços, mas infelizmente ele não parece resolver qualquer uma das minhas perguntas. Ou seja, a opção vazia / traços ainda aparece na lista.

Publicado 11/04/2009 em 01:43
fonte usuário
Em outras línguas...                            


15 respostas

votos
80

Não testei isso, mas com base na leitura de código do Django aqui e aqui eu acredito que deve funcionar:

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 : Este é documentado , embora você não necessariamente sabe que procurar ModelChoiceField se você estiver trabalhando com um ModelForm gerado automaticamente.

EDIT : Como observa jlpp em sua resposta, este não está completo - você tem que voltar a atribuir as escolhas para os widgets depois de mudar o atributo empty_label. Desde que é um pouco hacky, a outra opção que pode ser mais fácil de entender é apenas substituindo toda a ModelChoiceField:

class ThingForm(models.ModelForm):
  verb = ModelChoiceField(Verb.objects.all(), empty_label=None)

  class Meta:
    model = Thing
Respondeu 11/04/2009 em 13:40
fonte usuário

votos
32

a partir dos documentos

A escolha em branco não serão incluídos se o campo de modelo tem blank = False e um valor padrão explícito (o valor padrão será inicialmente selecionados, em vez).

assim definir o padrão e você está ok

Respondeu 11/04/2009 em 01:58
fonte usuário

votos
22

Com a resposta de Carl como um guia e depois de enraizamento em torno da fonte Django por algumas horas eu acho que esta é a solução completa:

  1. Para remover a opção vazio (estendendo-se o exemplo de Carl):

    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. Para personalizar a etiqueta opção vazia é essencialmente o mesmo:

    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
    

Penso que esta abordagem se aplica a todos os cenários onde ModelChoiceFields são processados ​​como HTML, mas eu não sou positivo. Descobri que quando esses campos são inicializados, suas escolhas são passados ​​para o Select widget (veja django.forms.fields.ChoiceField._set_choices). Definir o empty_label após a inicialização não atualiza lista Selecionar do widget de escolhas. Eu não estou bastante familiarizado com Django saber se isso deve ser considerado um bug.

Respondeu 12/04/2009 em 06:13
fonte usuário

votos
17

Você pode usar isso em seu modelo:

class MyModel(models.Model):
    name = CharField('fieldname', max_length=10, default=None)

default = None é a resposta: D

NOTA: Eu tentei isso em Django 1.7

Respondeu 21/07/2014 em 16:22
fonte usuário

votos
8

Quanto ao Django 1.4 tudo que você precisa é definir o valor "default" e "blank = False" no campo de escolhas

class MyModel(models.Model):
    CHOICES = (
        (0, 'A'), 
        (1, 'B'),
    )
    choice_field = models.IntegerField(choices=CHOICES, blank=False, default=0)
Respondeu 30/07/2012 em 13:50
fonte usuário

votos
5

você pode fazer isso em admin:

formfield_overrides = {
    models.ForeignKey: {'empty_label': None},
}
Respondeu 27/04/2013 em 11:52
fonte usuário

votos
5

Veja aqui o debate completo sobre e métodos para a resolução desta questão.

Respondeu 01/09/2009 em 16:29
fonte usuário

votos
4

self.fields['xxx'].empty_value = Nonenão iria funcionar Se você tipo de campo é TypedChoiceFieldque não têm empty_labelpropriedade.

O que devemos fazer é remover primeira escolha:

1. Se você quer construir uma BaseFormauto detectarTypedChoiceField

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.Only uma forma poucos, você pode usar:

class AddClientForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(AddClientForm, self).__init__(*args, **kwargs)
        self.fields['xxx'].choices = self.fields['xxx'].choices[1:]
Respondeu 24/05/2015 em 09:03
fonte usuário

votos
2

Para um ForeignKeycampo, definindo o defaultvalor a ''no modelo irá remover a opção em branco.

verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')

Para outros campos, como CharFieldvocê pode definir o defaultque None, mas isso não funciona para ForeignKeycampos no Django 1.11.

Respondeu 21/09/2017 em 14:55
fonte usuário

votos
2

Para a versão mais recente do Django a primeira resposta deveria ser assim

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)`
Respondeu 27/03/2015 em 14:33
fonte usuário

votos
2

Eu estava brincando com isso hoje e só veio com um covarde hack solução bacana:

# 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,)

Agora você pode ajustar o padrão ModelChoiceFieldetiqueta vazia para qualquer coisa que você gostaria. :-)

PS: Não há necessidade de downvotes, patches de macaco não-prejudiciais estão sempre à mão.

Respondeu 12/01/2014 em 07:13
fonte usuário

votos
1

Acho SOLUÇÃO !!

Mas não para ForeignKey :-)

Talvez eu possa te ajudar. Eu olhei no código fonte Django e descobriu que em django.forms.extras.widgets.SelecteDateWidget () é uma propriedade chamada none_value que é igual a (0, '-----') assim que eu fiz no meu código este

class StudentForm(ModelForm):
    class Meta:
        this_year = int(datetime.datetime.today().strftime('%Y')) 
        birth_years = []
        years = []

        for year in range(this_year - 2, this_year + 3 ):
            years.append(year)
        for year in range(this_year - 60, this_year+2):
            birth_years.append(year)

        model = Student
        exclude = ['user', 'fullname']
        date_widget = SelectDateWidget(years=years)

        date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
        widgets = {
            'beginning': date_widget,
            'birth': SelectDateWidget(years=birth_years),
        }
Respondeu 14/02/2014 em 17:52
fonte usuário

votos
0

Isto torna-se mais complicado quando as escolhas são chaves estrangeiras e se você quiser filtrar as escolhas com base em alguns critérios . Nesse caso, se você definir a empty_labele, em seguida, re-atribuir as opções (você pode aplicar filtração aqui também) o rótulo vazio ficará em branco:

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, a primeira linha sob initpodem ser aplicados para todos os campos do formulário com um loop ou de loop in-line:

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
Respondeu 23/08/2018 em 23:46
fonte usuário

votos
0

Desde Django 1.7, você pode personalizar a etiqueta para o valor em branco, adicionando um valor à sua lista de escolhas em sua definição de campo de modelo. A partir da documentação sobre a configuração de opções de campo :

A menos que blank = False está situado no campo junto com um padrão, em seguida, um rótulo contendo "---------" será processado com a caixa de seleção. Para substituir esse comportamento, adicione uma tupla a escolhas contendo Nenhum; eg (None, 'Seu String Para Display'). Alternativamente, você pode utilizar uma string vazia em vez de Nenhum onde isso faz sentido - como em um CharField.

Eu verifiquei a documentação para diferentes versões do Django e descobriu que este foi adicionado em Django 1.7 .

Respondeu 26/04/2018 em 18:18
fonte usuário

votos
0

Há lotes de grandes respostas aqui, mas eu ainda não estou totalmente satisfeito com as implementações. Eu também estou um pouco frustrado que os widgets selecionados de diferentes fontes (chaves estrangeiras, escolhas) geram comportamentos diferentes.

Eu tenho um projeto que eu estou trabalhando com o local onde selecione campos sempre tem uma opção em branco, e se eles são necessários terão uma estrela ao lado deles e a forma simplesmente não irá validar se é deixado vazio. Dito isto, eu posso substituir única corretamente o empty_label para campos que não são TypedChoiceFields.

Aqui está o que o resultado deve ser parecida. O primeiro resultado é sempre o nome do campo - no meu caso, a label.

selecione Widget

Aqui está o que eu acabei fazendo. A seguir, um sobrescrito __init__método de minha forma:

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]]
Respondeu 14/02/2018 em 04:17
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more