我能够使用this answer 中给出的相同技术。它非常适用于CheckboxSelectMultiple,尽管它没有在答案中使用。
我把它保存在我项目的forms.py:
from django.forms.widgets import CheckboxSelectMultiple, Select
class SelectWithAttrs(Select):
"""
Select With Option Attributes:
Subclass of Django's Select widget that allows attributes in options,
e.g. disabled="disabled", title="help text", class="some classes",
style="background: color;", etc.
Pass a dict instead of a string for its label:
choices = [ ('value_1', 'label_1'),
...
('value_k', {'label': 'label_k', 'foo': 'bar', ...}),
... ]
The option k will be rendered as:
<option value="value_k" foo="bar" ...>label_k</option>
"""
def create_option(self, name, value, label, selected, index,
subindex=None, attrs=None):
if isinstance(label, dict):
opt_attrs = label.copy()
label = opt_attrs.pop('label')
else:
opt_attrs = {}
option_dict = super().create_option(
name, value, label, selected, index,
subindex=subindex, attrs=attrs)
for key, val in opt_attrs.items():
option_dict['attrs'][key] = val
return option_dict
class CheckboxSelectMultipleWithAttrs(
SelectWithAttrs, CheckboxSelectMultiple):
pass
这是我的一个项目中使用此示例的工作 sn-p。一开始的内容并不重要,但它展示了如何构建您的属性字典并将其传递给您的choices。
from django import forms
from django.whatever import other_stuff
from project_folder import forms as project_forms
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['employees']
def __init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self.fields['employees'].queryset =\
self.company.employee_set.filter(is_active=True)
existing_crews_employees = []
for crew in existing_job_crews:
crew_employees =\
[employee.__str__() for employee in crew.employees.all()]
existing_crews_employees.append({'crew_name': crew.crewtype.name,
'employees': crew_employees})
employees_choices = []
for (index, choice) in enumerate(self.fields['employees'].choices):
# loop over each choice and set proper paramaters for employees
# that are unassigned/on the current crew/on a different crew
employee_in_crew = False
employee_name = choice[1]
for crew_and_employees in existing_crews_employees:
for employee in crew_and_employees['employees']:
if employee_name == employee.__str__():
crew_name = crew_and_employees['crew_name']
if self.obj and self.obj.crewtype.name == crew_name:
# check the box if employee in current crew
employees_choices.append((choice[0], {
'label': choice[1],
'checked': True,
'id': f'id_employees_{choice[0].instance.id}'
}))
else:
# disable the choice if employee in another crew
employees_choices.append((choice[0], {
'label':
employee_name + f" (on Crew: {crew_name})",
'disabled': True}))
employee_in_crew = True
# for valid entries, ensure that we pass the proper ID
# so that clicking the label will also check the box
if not employee_in_crew:
employees_choices.append((choice[0], {
'label': choice[1],
'id': f'id_employees_{choice[0].instance.id}'}))
self.fields['employees'].widget = project_forms.CheckboxSelectMultipleWithAttrs(
choices=employees_choices)
在使用此技术时要牢记两件重要的事情:
- 确保将
id 传递到您的 attrs 以获得可点击选项,否则您的标签在被点击时不会选中正确的框。
- 此方法当前需要使用新属性 dict 设置初始值。确保将
'checked': True 键值对传递给任何应选中的框。