Django:如何添加动态类来选择表单中的选项

时间:2014-09-03 21:48:39

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

我有一个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字段,但是对象的其他属性没有传递给这些函数。

我觉得我正在努力做一个简单的解决方案。任何帮助将非常感激!

3 个答案:

答案 0 :(得分:2)

我猜你可以这样做(注意'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>

答案 1 :(得分:0)

我认为在向选项元素添加类或其他任何内容时存在问题。我知道某些情况适用于CSS,请参阅此其他帖子,例如:Can we add class attribute in option element? 我认为同样可能适用于使用JavaScript操纵它。

这可能有点棘手,但也许在模板中让它写出一些将{{object.id}}映射到{{object.otherProperty}}的JavaScript,这样你就可以访问这个值了

答案 2 :(得分:0)

你可以试试这个。

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>