2009-10-24 17 views
7

Ho un campo multivalore con un campo di battaglia e un campo di scelta. Devo passare delle scelte al costruttore del campo di scelta, tuttavia quando provo a passarlo nel mio multivalore personalizzato, ottengo un errore __init__() ottenuto un '"opzione" di parole chiave inaspettate.Django MultiValueField - Come passare le scelte a ChoiceField?

So che il resto del codice funziona perché quando rimuovo l'argomento della parola chiave scelte da __init__ e super, il campo multivalore viene visualizzato correttamente ma senza alcuna scelta.

è così che ho installato il mio personalizzato multivaluefield:

class InputAndChoice(object): 
    def __init__(self, text_val='', choice_val=''): 
     self.text_val=text_val 
     self.choice_val=choice_val 

class InputAndChoiceWidget(widgets.MultiWidget): 
    def __init__(self, attrs=None): 
     widget = (widgets.TextInput(), 
        widgets.Select() 
       ) 
     super(InputAndChoiceWidget, self).__init__(widget, attrs=attrs) 

    def decompress(self,value): 
     if value: 
      return [value.text_val, value.choice_val] 
     return [None, None] 


class InputAndChoiceField(forms.MultiValueField): 
    widget = InputAndChoiceWidget 

    def __init__(self, required=True, widget=None, label=None, initial=None, 
       help_text=None, choices=None): 
     field = (
       fields.CharField(), 
       fields.ChoiceField(choices=choices), 
       ) 
     super(InputAndChoiceField, self).__init__(fields=field, widget=widget, 
       label=label, initial=initial, help_text=help_text, choices=choices) 

E io lo chiamo in questo modo:

input_and_choice = InputAndChoiceField(choices=[(1,'first'),(2,'second')]) 

Quindi, come faccio a passare le scelte per il mio campo ChoiceField?

Edit:

Ho provato il suggerimento di stefanw ma ancora fortuna. Ho usato logging.debug per stampare il contenuto di InputAndChoiceField alla fine di init e self.fields [1] .choices contiene i valori corretti come sopra, tuttavia non visualizza alcuna scelta nel browser.

risposta

1

Date un'occhiata alla fonte di __init__ di forms.MultiValueField:

def __init__(self, fields=(), *args, **kwargs): 
    super(MultiValueField, self).__init__(*args, **kwargs) 
    # Set 'required' to False on the individual fields, because the 
    # required validation will be handled by MultiValueField, not by those 
    # individual fields. 
    for f in fields: 
     f.required = False 
    self.fields = fields 

Quindi mi sento di sovrascrivere il __init__ probabilmente come questo:

def __init__(self, *args, **kwargs): 
    choices = kwargs.pop("choices",[]) 
    super(InputAndChoiceField, self).__init__(*args, **kwargs) 
    self.fields = (
     fields.CharField(), 
     fields.ChoiceField(choices=choices), 
    ) 

Si potrebbe anche voler fare super(MultiValueField, self).__init__(*args, **kwargs) invece di super(InputAndChoiceField, self).__init__(*args, **kwargs) perché stai impostando i campi tu stesso invece di ottenerli tramite parametri.

+0

Ho appena provato questo, ma ho ancora un campo di scelta vuoto. Ho controllato e le scelte sono passate correttamente però. qualche idea? –

+0

Sembra che si debba costruire un oggetto 'fields' prima di chiamare il costruttore di MultiValueField, e quindi passare quel valore 'fields' nel primo parametro del contructor della superclasse. – mjumbewu

1

passando le scelte nel widget risolto questo per me

class InputAndChoiceWidget(widgets.MultiWidget): 
    def __init__(self, attrs=None): 
     choices = [('a', 1), ('b', 2)] 
     widget = (widgets.TextInput(), 
        widgets.Select(choices=choices) 
       ) 
     super(InputAndChoiceWidget, self).__init__(widget, attrs=attrs) 
2

mi sono imbattuto in questo stesso problema e risolto in questo modo:

class InputAndChoiceWidget(widgets.MultiWidget): 
    def __init__(self,*args,**kwargs): 
     myChoices = kwargs.pop("choices") 
     widgets = (
      widgets.TextInput(), 
      widgets.Select(choices=myChoices) 
     ) 
     super(InputAndChoiceWidget, self).__init__(widgets,*args,**kwargs) 

class InputAndChoiceField(forms.MultiValueField): 
    widget = InputAndChoiceWidget 

    def __init__(self,*args,**kwargs): 
     # you could also use some fn to return the choices; 
     # the point is, they get set dynamically 
     myChoices = kwargs.pop("choices",[("default","default choice")]) 
     fields = (
      fields.CharField(), 
      fields.ChoiceField(choices=myChoices), 
     ) 
     super(InputAndChoiceField,self).__init__(fields,*args,**kwargs) 
     # here's where the choices get set: 
     self.widget = InputAndChoiceWidget(choices=myChoices) 

Aggiungi un kwarg "scelte" per il widget del costruttore. Quindi chiamare esplicitamente il costruttore dopo la creazione del campo.

+0

Questo esempio farà sì che 'InputAndChoiceWidget .__ init __()' venga chiamato due volte e, a causa del kwars.pop, si otterrà un'eccezione keyError. Ho risolto questo problema rimuovendo la riga 'widget = InputAndChoiceWidget' – isaac

+0

Sei corretto. Colpa mia. – trubliphone

0
class HTML5DateInput(DateInput): 

    input_type = 'date' 


class CustomSelectRangeWidget(forms.MultiWidget): 

    def __init__(self, attrs=None, choices =()): 
     widgets = (Select(attrs=attrs, choices=choices), HTML5DateInput(attrs=attrs), HTML5DateInput(attrs=attrs)) 
     super(CustomSelectRangeWidget, self).__init__(widgets, attrs) 

    def decompress(self, value): 
     if value: 
      return [value.field, value.start, value.stop] 
     return [None, None, None] 

    def format_output(self, rendered_widgets): 
     return '-'.join(rendered_widgets) 

class CustomSelectRangeField(forms.MultiValueField): 

    widget = CustomSelectRangeWidget 

    def __init__(self, *args, **kwargs): 
     if kwargs.has_key('choices') : 
      choices = kwargs.pop('choices') 
     else: 
      choices =() 
     fields = (
      forms.ChoiceField(choices=choices), #field with choices, 
              # so that clean can be passed 
      forms.DateField(), 
      forms.DateField(), 
      ) 
     super(CustomSelectRangeField, self).__init__(fields=fields, *args, **kwargs) 
     #initialize widget with choices. 
     self.widget = CustomSelectRangeWidget(choices=choices) 

    def compress(self, data_list): 
     if data_list: 
      #check if datalist has 3 not null values 
      if len([v for v in data_list if v not in [None, '']]) == 3: 
       out_dict = {'field':data_list[0], 'start':data_list[1], 'stop':data_list[2]} 
       return out_dict 
     return None 
+0

Questo è il mio problema per quanto riguarda le scelte nel campo di selezione. È una composizione di 3 campi, 1 campo Choice e altri 2 DateInput –

0

ModelChoiceField is technically a ChoiceField, ma in realtà non utilizzare uno dei implementazioni s' il ChoiceField. Quindi, ecco come lo uso.

class ChoiceInputMultiWidget(MultiWidget): 
    """Kindly provide the choices dynamically""" 
    def __init__(self, attrs=None): 
     _widget = (
      Select(attrs=attrs), 
      TextInput(attrs=attrs) 
     ) 
     super().__init__(_widget, attrs) 

class ModelChoiceInputField(MultiValueField): 
    widget = ChoiceInputMultiWidget 

    def __init__(self, *args, **kwargs): 

     _fields = (
      ModelChoiceField(queryset=Type.objects.all()), 
      CharField() 
     ) 
     super().__init__(_fields, *args, **kwargs) 

     # Use the auto-generated widget.choices by the ModelChoiceField 
     self.widget.widgets[0].choices = self.fields[0].widget.choices 
Problemi correlati