【问题标题】:Django: How to add dynamic classes to select options in a formDjango:如何添加动态类以选择表单中的选项
【发布时间】:2014-10-28 12:53:43
【问题描述】:

我有一个 ModelForm,我正在使用 django-widget-tweaks 在模板中进行渲染。我有一个 ChoiceField 选择,打印出如下内容:

<select>
    <option value="object.id">object.name</option>
</select>

但出于 Javascript 操作的目的,我需要以下内容:

<select>
    <option value="object.id" class="object.otherPropery">object.name</option>
</select>

django-widget-tweaks has an add_class function,但它只向选择框添加一个类,而不是包含的选项。

我也尝试过滚动自己的选择框:

<select>
    {% for object in form.object_field %}
        <option value="{{ object.id }}" class="{{ object.otherProperty }}">{{ object.name }}</option>
    {% endfor %}
</select>

但是当表单没有验证并返回错误时,用户之前选择的选项会重置为默认(第一个)选项(这确实发生在 django-widget-tweaks 中) .

我也尝试过覆盖 Select 小部件的 render_optionrender_options 字段,但对象的其他属性并未传递给这些函数。

我觉得我正在尝试做的事情有一个简单的解决方案。任何帮助将非常感激!

【问题讨论】:

    标签: django django-forms django-templates django-widget


    【解决方案1】:

    我猜你可以这样做(注意'if'标签):

    <select>
        {% with value=form.object_field.value %}
            {% for object in form.object_field %}
                <option 
                    value="{{ object.id }}" 
                    class="{{ object.otherProperty }}"
                    {% if object.id == value %}selected="selected"{% endif %}
                >
                    {{ object.name }}
                </option>
           {% endfor %}
        {% endwith %}
    </select>
    

    虽然 if 条件可能不会在它应该得到一个真实的结果时,如果 object.id 是一个整数,因为 value 将始终是一个已提交表单的字符串(POST/GET 中的所有值查询数据是字符串)。但如果该值来自“initial_data”,它将是整数。

    对于这种情况,您可以按如下方式更新您的“if”标签:

    {% if object.id|slugify == value|slugiy %}selected="selected"{% endif %}
    

    制作最终代码如下:

    <select>
        {% with value=form.object_field.value %}
            {% for object in form.object_field %}
                <option 
                    value="{{ object.id }}" 
                    class="{{ object.otherProperty }}"
                    {% if object.id|slugify == value|slugify %}selected="selected"{% endif %}
                >
                    {{ object.name }}
                </option>
           {% endfor %}
        {% endwith %}
    </select>
    

    【讨论】:

      【解决方案2】:

      你可以试试这个。

      render_option 已从 Django 1.11 开始删除。这就是我为实现这一目标所做的。一点点挖掘,这似乎很简单。适用于 Django 2.0+

      class CustomSelect(forms.Select):
          def __init__(self, attrs=None, choices=()):
              self.custom_attrs = {}
              super().__init__(attrs, choices)
      
          def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
              index = str(index) if subindex is None else "%s_%s" % (index, subindex)
              if attrs is None:
                  attrs = {}
              option_attrs = self.build_attrs(self.attrs, attrs) if self.option_inherits_attrs else {}
              if selected:
                  option_attrs.update(self.checked_attribute)
              if 'id' in option_attrs:
                  option_attrs['id'] = self.id_for_label(option_attrs['id'], index)
      
              # setting the attributes here for the option
              if len(self.custom_attrs) > 0:
                  if value in self.custom_attrs:
                      custom_attr = self.custom_attrs[value]
                      for k, v in custom_attr.items():
                          option_attrs.update({k: v})
      
              return {
                  'name': name,
                  'value': value,
                  'label': label,
                  'selected': selected,
                  'index': index,
                  'attrs': option_attrs,
                  'type': self.input_type,
                  'template_name': self.option_template_name,
              }
      
      
      class MyModelChoiceField(ModelChoiceField):
      
          # custom method to label the option field
          def label_from_instance(self, obj):
              # since the object is accessible here you can set the extra attributes
              if hasattr(obj, 'type'):
                  self.widget.custom_attrs.update({obj.pk: {'type': obj.type}})
              return obj.get_display_name()
      

      形式:

      class BookingForm(forms.ModelForm):
      
          customer = MyModelChoiceField(required=True,
                                        queryset=Customer.objects.filter(is_active=True).order_by('name'),
                                        widget=CustomSelect(attrs={'class': 'chosen-select'}))
      

      我需要的输出如下:

        <select name="customer" class="chosen-select" required="" id="id_customer">
            <option value="" selected="">---------</option>
            <option value="242" type="CNT">AEC Transcolutions Private Limited</option>
            <option value="243" type="CNT">BBC FREIGHT CARRIER</option>
            <option value="244" type="CNT">Blue Dart Express Limited</option>
      

      【讨论】:

        【解决方案3】:

        我认为向选项元素添加类或其他任何内容存在问题。我肯定知道 CSS 的应用程序,例如,请参阅其他帖子:Can we add class attribute in option element? 我认为这同样适用于使用 JavaScript 操作它。

        这可能有点棘手,但也许在模板中写出一些将 {{ object.id }} 映射到 {{ object.otherProperty }} 的 JavaScript,这样您就可以通过这种方式访问​​值.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-15
          • 2023-03-06
          • 2021-03-14
          • 1970-01-01
          • 1970-01-01
          • 2011-08-31
          • 2019-03-21
          相关资源
          最近更新 更多