覆盖django的CheckboxSelectMultiple小部件for Awesome Bootstrap复选框 [英] Overriding django's CheckboxSelectMultiple widget for Awesome Bootstrap Checkboxes

查看:190
本文介绍了覆盖django的CheckboxSelectMultiple小部件for Awesome Bootstrap复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在模板中打印以下表单的实例:

If I print an instance of the following form in a template:

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>

这些嵌入在标签中的输入基本上是嵌入在列表项中的。

This is basically bunch of inputs embedded in labels, which are embedded in list items.

对于令人敬畏的Bootstrap复选框要工作,我需要改变一下布局。具体来说,输入必须高于不在其中的标签。此外,输入和标签都需要包含在一个 div 中,类checkbox checkbox-primary,而不是 li

For Awesome Bootstrap Checkboxes to work I need to change the layout a bit. Specifically, inputs must be above the labels not in them. Also, both the input and the label need to wrapped in a div with class "checkbox checkbox-primary", instead of a li.

对于上述示例,这将是:

For the above example this would be:

<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的现有的?

How can I accomplish this by defining a new widget, preferably overriding django's existing?

推荐答案

这是django在执行顺序或类层次结构中的默认代码:

Here is django's default code in execution order or class hierarchy:

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
        )
    ...

现在我们反过来覆盖必要的部分: / p>

And now we override necessary parts in reverse:

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

这篇关于覆盖django的CheckboxSelectMultiple小部件for Awesome Bootstrap复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆