2009-10-24 11 views
7

Posiadam pole wielozadaniowości z charfield i polem wyboru. Muszę przekazać wybory konstruktorowi choicefield, jednak gdy próbuję go przekazać na moje niestandardowe pole multivaluefield, pojawia się błąd __init__() otrzymuję nieoczekiwany argument słowa kluczowego "wybory".Django MultiValueField - Jak przekazywać wybory do ChoiceField?

Wiem, że reszta kodu działa, ponieważ po usunięciu argumentu słowa kluczowego wyboru z __init__ i super, pole multivaluefield wyświetla się poprawnie, ale bez możliwości wyboru.

ten sposób mogę skonfigurować mój zwyczaj 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) 

A ja nazywam to tak:

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

Więc jak mam przekazać wyborów do mojej dziedzinie ChoiceField?

Edit:

Próbowałem sugestię stefanw, ale nadal nie ma szczęścia. Użyłem logging.debug do wydrukowania zawartości InputAndChoiceField na końcu init i self.fields [1] .choices zawiera poprawne wartości jak wyżej, jednak nie wyświetla żadnych opcji w przeglądarce.

Odpowiedz

1

Wystarczy popatrzeć na źródło __init__ z 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 

Więc chciałbym zastąpić __init__ prawdopodobnie tak:

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

Można nawet chcą zrobić super(MultiValueField, self).__init__(*args, **kwargs) zamiast super(InputAndChoiceField, self).__init__(*args, **kwargs) ponieważ ustawiasz pola samodzielnie, zamiast odbierać je za pomocą parametrów.

+0

Po prostu próbowałem, ale nadal mam puste pole wyboru. Sprawdziłem i opcje są jednak poprawnie przekazywane. jakieś pomysły? –

+0

Wygląda na to, że powinieneś skonstruować obiekt 'fields' przed wywołaniem konstruktora MultiValueField, a następnie przekazać tę wartość 'fields' do pierwszego parametru contructor nadklasy. – mjumbewu

1

przechodząc wyborów w widgecie rozwiązać to dla mnie

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

wpadłem na taką sam problem i rozwiązać go tak:

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) 

Dodaj „wybory” kwarg do widgetu konstruktor. Następnie jawnie wywołaj konstruktora po utworzeniu pola.

+0

Ten przykład spowoduje, że 'InputAndChoiceWidget .__ init __()' zostanie wywołane dwa razy i z powodu kwars.pop otrzymasz wyjątek keyError. Usunąłem ten problem, usuwając linię 'widget = InputAndChoiceWidget' – isaac

+0

Masz rację. Mój błąd. – 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

To rozwiązuje mój problem dotyczący wyborów w polu wyboru. Składa się z 3 pól, 1 pola wyboru, a pozostałe 2 to DateInput –

Powiązane problemy