2009-10-24 2 views
7

У меня есть многозначное поле с charfield и choicefield. Мне нужно передать выбор конструктору выбора, однако, когда я пытаюсь передать его в свое настраиваемое многозначное поле, я получаю сообщение об ошибке. __init__() получил неожиданный аргумент аргументов ключевого слова.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 поле?

Edit:

Я попытался предложение stefanw, но до сих пор нет удачи. Я использовал logging.debug для распечатки содержимого InputAndChoiceField в конце init и self.fields [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

Я просто попробовал это, но я все равно получаю пустое поле выбора. Я проверил, и выбор прошел правильно, хотя. Есть предположения? –

+0

Похоже, вы должны создать объект 'fields' перед вызовом конструктора MultiValueField, а затем передать это значение 'fields' в первый параметр contructor суперкласса. – mjumbewu

1

передавая выбор в виджете решил это для меня

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 к виджету конструктор. Затем явным образом вызовите конструктор после создания поля.

+0

В этом примере вызывается 'InputAndChoiceWidget .__ init __()' для вызова дважды, и из-за kwars.pop вы получите исключение keyError. Я обошел эту проблему, удалив строку 'widget = InputAndChoiceWidget' – isaac

+0

Вы верны. Виноват. – 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

Это решает мою проблему относительно выбора в поле выбора. Это композиция из 3 полей, 1 поле выбора, а другие 2 - DateInput –

0

ModelChoiceField is technically a ChoiceField, но это на самом деле не использовать какие-либо из реализаций ChoiceField «s. Итак, вот как я его использую.

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 
Смежные вопросы