2009-10-24 9 views
7

Tôi có một multivaluefield với một charfield và choicefield. Tôi cần phải vượt qua các lựa chọn để các nhà xây dựng choicefield, tuy nhiên khi tôi cố gắng vượt qua nó vào multivaluefield tùy chỉnh của tôi, tôi nhận được một lỗi __init__() có một đối số từ khóa bất ngờ 'lựa chọn'.Django MultiValueField - Cách chuyển các lựa chọn cho ChoiceField?

Tôi biết phần còn lại của mã hoạt động vì khi tôi xóa đối số từ khóa lựa chọn từ __init__ và siêu, trường đa giá trị hiển thị chính xác nhưng không có bất kỳ lựa chọn nào.

Đây là cách tôi thiết lập của tôi multivaluefield tùy chỉnh:

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) 

Và tôi gọi nó như vậy:

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

Vì vậy, làm thế nào để tôi vượt qua những lựa chọn để lĩnh vực ChoiceField của tôi?

Chỉnh sửa:

Tôi đã thử đề xuất của stefanw nhưng vẫn không có may mắn. Tôi đã sử dụng logging.debug để in ra các nội dung của InputAndChoiceField ở cuối init và self.fields [1] .choices chứa các giá trị đúng như trên, tuy nhiên nó không hiển thị bất kỳ lựa chọn nào trong trình duyệt.

Trả lời

1

Có xem xét nguồn gốc của __init__ của 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 

Vì vậy, tôi sẽ ghi đè lên __init__ lẽ như thế này:

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

Bạn thậm chí có thể muốn làm super(MultiValueField, self).__init__(*args, **kwargs) thay vì super(InputAndChoiceField, self).__init__(*args, **kwargs) vì bạn tự thiết lập các trường thay vì nhận chúng thông qua các tham số.

+0

Tôi vừa thử điều này nhưng tôi vẫn nhận được trường lựa chọn trống. Tôi đã kiểm tra và các lựa chọn được thông qua một cách chính xác mặc dù. Có suy nghĩ gì không? –

+0

Có vẻ như bạn nên xây dựng một đối tượng 'trường' trước khi gọi hàm tạo MultiValueField, và sau đó chuyển giá trị 'trường' đó vào tham số đầu tiên của đối tượng siêu lớp. – mjumbewu

1

đi qua các lựa chọn trong các phụ tùng giải quyết này cho tôi

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

Tôi chạy vào cùng một vấn đề này chính xác và giải quyết nó như thế này:

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) 

Thêm một "lựa chọn" kwarg để các phụ tùng của constructor. Sau đó gọi một cách rõ ràng hàm tạo sau khi trường được tạo.

+0

Ví dụ này sẽ khiến 'InputAndChoiceWidget .__ init __()' được gọi hai lần và vì kwars.pop bạn sẽ nhận được một ngoại lệ keyError. Tôi gặp vấn đề này bằng cách xóa dòng 'widget = InputAndChoiceWidget' – isaac

+0

Bạn là chính xác. Lỗi của tôi. – 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

Điều này giải quyết được vấn đề của tôi liên quan đến các lựa chọn trong trường chọn. Đó là thành phần của trường 3 trường, trường Lựa chọn 1 và 2 thành phần khác là DateInput –

0

ModelChoiceField is technically a ChoiceField nhưng không thực sự sử dụng bất kỳ triển khai nào của ChoiceField. Vì vậy, đây là cách tôi sử dụng nó.

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