访问 CheckboxSelectMultiple 复选框的属性

Posted

技术标签:

【中文标题】访问 CheckboxSelectMultiple 复选框的属性【英文标题】:Accessing Attributes of a CheckboxSelectMultiple checkbox 【发布时间】:2019-02-22 19:31:03 【问题描述】:

短版

在 Django 模板语言中,如何访问 CheckboxSelectMultiple 小部件中给定复选框的属性?

加长版

可以轻松访问典型 Django 小部件的属性:

% for field in form %
 field.widget.attrs.something 
% endfor %

但是,此方法不适用于CheckboxSelectMultiple 小部件的复选框。

我有一个自定义的 CheckboxSelectMultiple 小部件,我用它来显示 ManyToMany ModelForm 字段。自定义小部件为 create_option 方法中的每个复选框添加了额外的属性。

附加属性在输入元素的 html 中适当显示:

<input type="checkbox" name="questions" value="22" id="id_questions_12" category="Category Name" category_number="3" question="Question Name" question_number="4">

为了显示和组织表单字段,我需要访问这些附加属性。

【问题讨论】:

【参考方案1】:

在放置一周左右后,我又回到了这个问题。在玩了更多并阅读了BoundField(特别是BoundWidget)的文档之后,我发现了如何访问CheckboxSelectMultiple小部件中单个复选框的attrs

% for field in form %
% for check in field.subwidgets %
% for a in check.data.attrs %

【讨论】:

【参考方案2】:

我能够使用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 键值对传递给任何应选中的框。

【讨论】:

以上是关于访问 CheckboxSelectMultiple 复选框的属性的主要内容,如果未能解决你的问题,请参考以下文章

Django Admin Template Overriding:显示 checkboxselectmultiple 小部件

django checkboxSelectMultiple

Wagtail admin,CheckboxSelectMultiple不保存数据

Django CheckboxSelectMultiple 覆盖 ModelForm 中的“选择”

如何在不覆盖 ModelForm 中的字段定义的情况下将 ManyToManyField 小部件更改为 CheckboxSelectMultiple

Django Modelmultiplechoicefield Checkboxselectmultiple 获取选中复选框的问题