2009-10-24 86 views
7

我有一個charfield和choicefield的多值域。我需要將選擇傳遞給choicefield構造函數,但是當我嘗試將其傳遞到我的自定義多值字段時,出現錯誤__init__()得到了一個意外的關鍵字參數'choices'。Django MultiValueField - 如何將選項傳遞給ChoiceField?

我知道其餘代碼的作品,因爲當我從__init__和超級刪除選項關鍵字參數時,多值字段顯示正確,但沒有任何選擇。

這是怎麼設置我的自定義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) 

我叫它像這樣:

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

那麼,如何通過選擇,我ChoiceField場?

編輯:

我已經試過stefanw的建議,但仍然沒有運氣。我已經使用logging.debug在init和self.fields [1]的末尾打印出InputAndChoiceField的內容。[1] .choices包含上述正確的值,但它不會在瀏覽器中顯示任何選項。

回答

1

看一看__init__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 

因此,我將覆蓋__init__大概是這個樣子:

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

你甚至可能想要做super(MultiValueField, self).__init__(*args, **kwargs)而不是super(InputAndChoiceField, self).__init__(*args, **kwargs)因爲你自己設置字段而不是通過參數獲取它們。

+0

我剛試過這個,但我仍然得到一個空的選擇字段。我檢查了,但選擇正確通過。有什麼想法嗎? – 2009-10-24 09:45:20

+0

它看起來應該在調用MultiValueField構造函數之前構造一個'fields'對象,然後將該'fields'值傳遞給超類構造函數的第一個參數。 – mjumbewu 2011-04-06 21:00:38

1

傳遞選擇在widget解決了這個對我來說

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

我就遇到了這個確切的同樣的問題,解決了這個問題是這樣的:

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) 

添加一個「選擇」 kwarg到Widget的構造函數。然後在創建字段後顯式調用構造函數。

+0

這個例子會導致'InputAndChoiceWidget .__ init __()'被調用兩次,並且由於kwars.pop,你會得到一個keyError異常。我通過刪除'widget = InputAndChoiceWidget'行來解決這個問題 – isaac 2012-04-18 22:24:59

+0

你是對的。我的錯。 – trubliphone 2012-04-19 15:47:21

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

這解決了我在選擇領域中的選擇問題。它是由3個字段組成的,1個選擇字段,另外2個是DateInput – 2013-05-21 07:11:21

0

ModelChoiceField is technically a ChoiceField,但它實際上並沒有使用任何ChoiceField的實現。所以,這是我如何使用它。

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 
相關問題