2009-10-24 93 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 
相关问题