【问题标题】:Accessing Attributes of a CheckboxSelectMultiple checkbox访问 CheckboxSelectMultiple 复选框的属性
【发布时间】: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">

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

【问题讨论】:

    标签: django django-forms django-templates


    【解决方案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 键值对传递给任何应选中的框。

      【讨论】:

        猜你喜欢
        • 2019-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-09
        • 2017-04-30
        • 2013-06-25
        相关资源
        最近更新 更多