1👍
✅
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
)
...
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
Source:stackexchange.com