2016-08-31 5 views
0

のためにDjangoのCheckboxSelectMultipleウィジェットをオーバーライド:は恐ろしいブートストラップチェックボックス

class StrategiesForm(forms.Form): 
    letters = MultipleChoiceField(
     choices=((0, 'a'),(1, 'b'),(2, 'c')), 
     label="a_label", 
     required=True, 
     widget=CheckboxSelectMultiple(), 
    ) 

私が取得:

<label for="id_letters_0">a_label:</label> 
<ul id="id_letters"> 
    <li> 
     <label for="id_letters_0"> 
      <input id="id_letters_0" name="letters" type="checkbox" value="0"> a 
     </label> 
    </li> 
    <li> 
     <label for="id_letters_1"> 
      <input id="id_letters_1" name="letters" type="checkbox" value="1"> b 
     </label> 
    </li> 
    <li> 
     <label for="id_letters_2"> 
      <input id="id_letters_2" name="letters" type="checkbox" value="2"> c 
     </label> 
    </li> 
</ul> 

これは、基本的には、ラベルに埋め込まれた入力の束でありますこれらはリストアイテムに埋め込まれています。

Awesome Bootstrap Checkboxesの場合、レイアウトを少し変更する必要があります。具体的には、入力はその中にないラベルの上になければなりません。また、入力とラベルの両方を、liではなく、「checkbox checkbox-primary」クラスのdivにラップする必要があります。

上記の例では、これは次のようになります。

<label for="id_letters_0">a_label:</label> 
<div id="id_letters"> 
    <div class="checkbox checkbox-primary"> 
     <input id="id_letters_0" name="letters" type="checkbox" value="0"> a 
     <label for="id_letters_0"></label> 
    </div> 
    <div class="checkbox checkbox-primary"> 
     <input id="id_letters_1" name="letters" type="checkbox" value="1"> b 
     <label for="id_letters_1"></label> 
    </div> 
    <div class="checkbox checkbox-primary"> 
     <input id="id_letters_2" name="letters" type="checkbox" value="2"> c 
     <label for="id_letters_2"></label> 
    </div> 
</div> 

私は、好ましくは、Djangoの既存を上書き、新しいウィジェットを定義することによってこれを実現するにはどうすればよいですか?

+0

私もジャンゴ・bootstrap3アプリを使用しています。上記のウィジェットがうまくいけばうまくいくでしょう。 – mehmet

答えて

1

は、ここで実行順序やクラス階層内でDjangoのデフォルトのコードです:

class CheckboxSelectMultiple(RendererMixin, SelectMultiple): 
    renderer = CheckboxFieldRenderer   # contains all layout logic 
    _empty_value = [] 


class CheckboxFieldRenderer(ChoiceFieldRenderer): # parent has outer layout 
    choice_input_class = CheckboxChoiceInput # contains inner layout 


class ChoiceFieldRenderer(object):    # outer layout: ul and li 
    outer_html = '<ul{id_attr}>{content}</ul>' 
    inner_html = '<li>{choice_value}{sub_widgets}</li>' 

    def render(self):  # this generates inner layout, and wraps with outer 
     ... 

class CheckboxChoiceInput(ChoiceInput): 
    input_type = 'checkbox' 
    ... 


class ChoiceInput(SubWidget):     # inner layout: label and input 
    ... 
    def render(self, name=None, value=None, attrs=None, choices=()): 
     if self.id_for_label: 
      label_for = format_html(' for="{}"', self.id_for_label) 
     else: 
      label_for = '' 
     attrs = dict(self.attrs, **attrs) if attrs else self.attrs 
     return format_html(
      '<label{}>{} {}</label>', label_for, self.tag(attrs), self.choice_label 
     ) 
    ... 

そして今、我々は逆に、必要な部品を上書き:

class AwesomeChoiceInput(ChoiceInput): 
    def render(self, name=None, value=None, attrs=None, choices=()): 
     if self.id_for_label: 
      label_for = format_html(' for="{}"', self.id_for_label) 
     else: 
      label_for = '' 
     attrs = dict(self.attrs, **attrs) if attrs else self.attrs 
     return format_html(
      '{}\n<label{}> {}</label>', self.tag(attrs), label_for, self.choice_label # updated! 
     ) 


class AwesomeChoiceFieldRenderer(ChoiceFieldRenderer): 
    outer_html = '<div{id_attr}>{content}</div>'           # updated!! 
    inner_html = '<div class="checkbox checkbox-primary">{choice_value}{sub_widgets}</div>' # updated!! 
    def __init__(self, name, value, attrs, choices): 
     super().__init__(name, value, attrs, choices) 
     if 'awesome-class' in attrs: 
      self.inner_html = '<div class="checkbox ' + attrs.pop('awesome-class') + '">{choice_value}{sub_widgets}</div>' 

class AwesomeCheckboxChoiceInput(AwesomeChoiceInput, CheckboxChoiceInput): # this was little tricky 
    # there might be better ways of extending a class just to override its parent 
    # summary: class A(B) => class extendedA(extendedB, A) # to get whatever was in A also 
    pass 


class AwesomeCheckboxFieldRenderer(AwesomeChoiceFieldRenderer): # rest-just connect the pipes 
    choice_input_class = AwesomeCheckboxChoiceInput    # as you took off :)        


class AwesomeCheckboxSelectMultiple(CheckboxSelectMultiple): 
    renderer = AwesomeCheckboxFieldRendereraa 
関連する問題