web-dev-qa-db-fra.com

Label vide ChoiceField Django

Comment faites-vous pour que l'étiquette de ChoiceField se comporte comme ModelChoiceField? Est-il possible de définir un empty_label ou au moins d'afficher un champ vide?

Forms.py:

    thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
    color = forms.ChoiceField(choices=COLORS)
    year = forms.ChoiceField(choices=YEAR_CHOICES)

J'ai essayé les solutions suggérées ici:

Stack Overflow Q - Le paramètre CHOICES = [('','All')] + CHOICES a entraîné une erreur interne du serveur.

Débordement de pile Q2 - Après avoir défini ('', '---------'), dans mes choix, le premier élément de la liste par défaut, pas le choix ('', '---------'),

Gist - Essayé d'utiliser EmptyChoiceField défini ici, mais ne fonctionnant pas avec Django 1.4.

Mais aucun d’entre eux n’a fonctionné pour moi. Comment régleriez-vous ce problème? Merci pour vos idées!

32
Nick B

Voici la solution que j'ai utilisée:

from myapp.models import COLORS

COLORS_EMPTY = [('','---------')] + COLORS

class ColorBrowseForm(forms.Form):
    color = forms.ChoiceField(choices=COLORS_EMPTY, required=False, widget=forms.Select(attrs={'onchange': 'this.form.submit();'}))
12
Nick B

Voir la documentation de Django 1.11 sur ChoiceField . La valeur "empty_value" de ChoiceField est définie comme étant la chaîne vide ''; votre liste de tuples doit donc contenir une clé "" mappée sur la valeur que vous souhaitez afficher pour la valeur vide. 

### forms.py
from Django.forms import Form, ChoiceField

CHOICE_LIST = [
    ('', '----'), # replace the value '----' with whatever you want, it won't matter
    (1, 'Rock'),
    (2, 'Hard Place')
]

class SomeForm (Form):

    some_choice = ChoiceField(choices=CHOICE_LIST, required=False)

Notez que vous pouvez éviter une erreur de formulaire si vous souhaitez que le champ de formulaire soit facultatif en utilisant "required = False".

De même, si vous avez déjà une CHOICE_LIST sans une valeur vide, vous pouvez en insérer une de sorte qu'elle apparaisse en premier dans le menu déroulant du formulaire:

CHOICE_LIST.insert(0, ('', '----'))
33
Fiver

Vous pouvez essayer ceci (en supposant que vos choix soient des tuples):

blank_choice = (('', '---------'),)
...
color = forms.ChoiceField(choices=blank_choice + COLORS)
year = forms.ChoiceField(choices=blank_choice + YEAR_CHOICES)

De plus, je ne peux pas dire à partir de votre code s'il s'agit d'un formulaire ou d'un ModelForm, mais c'est le dernier, inutile de redéfinir le champ de formulaire ici (vous pouvez inclure les choix = COLORS et choix = YEAR_CHOICES directement dans le champ du modèle .

J'espère que cela t'aides. 

3
reczy

Je sais que vous avez déjà accepté une réponse, mais je veux simplement la poster au cas où quelqu'un tomberait sur le problème que j'avais, à savoir que la solution acceptée ne fonctionne pas avec un ValueListQuerySet. Le EmptyChoiceField , que vous avez lié à, fonctionne parfaitement pour moi (bien que j'utilise Django 1.7).

class EmptyChoiceField(forms.ChoiceField):
    def __init__(self, choices=(), empty_label=None, required=True, widget=None, label=None, initial=None, help_text=None, *args, **kwargs):

        # prepend an empty label if it exists (and field is not required!)
        if not required and empty_label is not None:
            choices = Tuple([(u'', empty_label)] + list(choices))

        super(EmptyChoiceField, self).__init__(choices=choices, required=required, widget=widget, label=label, initial=initial, help_text=help_text, *args, **kwargs) 

class FilterForm(forms.ModelForm):
    #place your other fields here 
    state = EmptyChoiceField(choices=People.objects.all().values_list("state", "state").distinct(), required=False, empty_label="Show All")
2
VT_Drew

Doit utiliser 0 au lieu de u '' à cause du champ entier dans le modèle. (Erreur: littéral non valide pour int () avec la base 10: ')

ajoutez une étiquette vide si elle existe (et le champ n'est pas obligatoire!)

    if not required and empty_label is not None:
        choices = Tuple([(0, empty_label)] + list(choices))
1
Pat

Un peu tard pour la fête ..

Pourquoi ne pas modifier les choix du tout et simplement le manipuler avec un widget?

from Django.db.models import BLANK_CHOICE_DASH

class EmptySelect(Select):
    empty_value = BLANK_CHOICE_DASH[0]
    empty_label = BLANK_CHOICE_DASH[1]

    @property
    def choices(self):
        yield (self.empty_value, self.empty_label,)
        for choice in self._choices:
            yield choice

    @choices.setter
    def choices(self, val):
        self._choices = val

Alors appelez ça:

class SomeForm(forms.Form):
    # thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
    color = forms.ChoiceField(choices=COLORS, widget=EmptySelect)
    year = forms.ChoiceField(choices=YEAR_CHOICES, widget=EmptySelect)

Naturellement, la EmptySelect serait placée dans une sorte de code common/widgets.py et ensuite chaque fois que vous en auriez besoin, faites-le simplement référence.

0
Javier Buzzi

Ce n'est pas la même forme, mais je l'ai fait de la manière suivante inspirée de la méthode EmptyChoiceField:

from Django import forms
from ..models import Operator


def parent_operators():
    choices = Operator.objects.get_parent_operators().values_list('pk', 'name')
    choices = Tuple([(u'', 'Is main Operator')] + list(choices))
    return choices


class OperatorForm(forms.ModelForm):
    class Meta:
        model = Operator
        # fields = '__all__'
        fields = ('name', 'abbr', 'parent', 'om_customer_id', 'om_customer_name', 'email', 'status')

    def __init__(self, *args, **kwargs):
        super(OperatorForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
        self.fields['abbr'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
        self.fields['parent'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
        self.fields['parent'].choices = parent_operators()
        self.fields['parent'].required = False
        self.fields['om_customer_id'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
        self.fields['om_customer_name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
        self.fields['email'].widget.attrs.update({'class': 'form-control m-input form-control-sm', 'type': 'email'})enter code here
0
cwhisperer