【问题标题】:Django add attributes to SelectMultiple <option> tagsDjango 为 SelectMultiple <option> 标签添加属性
【发布时间】:2017-09-17 08:44:59
【问题描述】:

here 在 django 表单字段中向 &lt;option&gt; 标签添加属性有很好的解释。但这仅适用于Select widget。我想为SelectMultiple widget 做同样的事情。

我尝试了以下方法(子类SelectSelectMultiple 并在创建Model 表单字段employees 时引用MySelectMultiple):

class MySelect(forms.Select):

    def __init__(self, *args, **kwargs):
            super(MySelect, self).__init__(*args, **kwargs)

    def render_option(self, selected_choices, option_value, option_label):
        # original forms.Select code #
        return u'<option custom_attribute="foo">...</option>'

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

employees = forms.ModelMultipleChoiceField(
                    widget=MySelectMultiple(attrs={}),
                    queryset=Employee.objects.all(),
                )

但呈现的表单仍显示为 Select 小部件,而不是 SelectMultiple 小部件。

我可以提供attrs={'multiple':'multiple'}MySelectMultiple 以使表单字段呈现为多选小部件 - 但是当保存表单时,只保存一个值(而不是多个值)!

如何将表单呈现为多选字段并保存所有选定的值?谢谢。

【问题讨论】:

  • 员工字段是多对多字段
  • @Thameem 是的。但请参阅下面的答案。
  • 默认情况下,多对多字段将呈现为 mutlipleselct 字段,并且当您调用 form.save() 时。它会自动保存这些值。那你为什么用这个
  • 是的,很好。但我这样做是为了向&lt;option&gt; 标签添加额外的属性——默认的SelectMultiple 小部件不提供这些属性。
  • 有一个适用于 Django 2.+ 的通用解决方案,并允许在选项中添加标题和其他内容,请参阅stackoverflow.com/a/56097149/1788851

标签: python django


【解决方案1】:

好的,想通了:通过使用:

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

我仍在使用 django 原生 Select,但只是将其称为 MySelectMultiple。我需要导入SelectMultiplerest

所以,而不是:

class MySelectMultiple(MySelect):
    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs) 

类需要完整(复制/粘贴SelectMultiple的原生django代码):

class MySelectMultiple(MySelect):
    allow_multiple_selected = True

    def __init__(self, *args, **kwargs):
        super(MySelectMultiple, self).__init__(*args, **kwargs)


    def render(self, name, value, attrs=None, choices=()):
        if value is None:
            value = []
        final_attrs = self.build_attrs(attrs, name=name)
        output = [format_html('<select multiple="multiple"{0}>', forms.utils.flatatt(final_attrs))]
        options = self.render_options(choices, value)
        if options:
            output.append(options)
        output.append('</select>')
        return mark_safe('\n'.join(output))

    def value_from_datadict(self, data, files, name):
        if isinstance(data, (MultiValueDict, MergeDict)):
            return data.getlist(name)
        return data.get(name, None)

【讨论】:

    【解决方案2】:

    您的选择倍数应继承自 SelectMultiple 而不是 Select

    class MySelectMultiple(SelectMultiple):
        def render_option(self, selected_choices, option_value, option_label):
            # original forms.Select code #
            return u'<option custom_attribute="foo">...</option>'
    

    看起来您的__init__ 方法不是必需的,因为它只是调用super()

    【讨论】:

    • 让我试一试。谢谢。
    • 你的答案和我的答案一样,但我的违反了 DRY,所以我同意你的。谢谢!
    【解决方案3】:

    SelectMultiple 继承自 Select,只需要重写 create_option 方法即可获得相同的结果:

    class MySelectMultiple(forms.SelectMultiple):
        def create_option(self, name, value, *args, **kwargs):
            option = super().create_option(name, value, *args, **kwargs)
            if value:
                instance = self.choices.queryset.get(pk=value)  # get instance
                option['attrs']['custom_attr'] = instance.field_name  # set option attribute
            return option
    
    

    【讨论】:

      猜你喜欢
      • 2014-12-03
      • 2013-07-04
      • 2011-09-22
      • 1970-01-01
      • 2022-10-04
      • 1970-01-01
      • 1970-01-01
      • 2019-09-19
      相关资源
      最近更新 更多