如何在Django中覆盖Model Form小部件?

时间:2016-02-16 06:34:48

标签: python django django-forms

我正在尝试覆盖render_option文件中Select Widget类中存在的forms.py方法。所以我在相应的Model表单类中添加了具有相同名称的方法。但它不起作用(这种方法无法覆盖)。我的forms.py文件看起来像,

class CustomSelectMultiple(Select):

    allow_multiple_selected = True

    def render_option(self, selected_choices, option_value, option_label):
        print 'Inside custom render_option\n\n'
        if option_value is None:
            option_value = ''
        option_value = force_text(option_value)
        if option_value in selected_choices:
            selected_html = mark_safe(' selected="selected"')
            if not self.allow_multiple_selected:
                # Only allow for a single selection.
                selected_choices.remove(option_value)
        else:
            selected_html = ''
        return format_html('<option value="{}" data-img-src="www.foo.com" {}>{}</option>',
                           option_value,
                           selected_html,
                           force_text(option_label))

    def render_options(self, choices, selected_choices):
        print 'Inside custom render_options\n\n'
        print self
        print choices
        # Normalize to strings.
        selected_choices = set(force_text(v) for v in selected_choices)
        output = []
        for option_value, option_label in chain(self.choices, choices):
            if isinstance(option_label, (list, tuple)):
                output.append(format_html('<optgroup label="{}">', force_text(option_value)))
                for option in option_label:
                    output.append(self.render_option(selected_choices, *option))
                output.append('</optgroup>')
            else:
                output.append(self.render_option(selected_choices, option_value, option_label))
        #print output
        return '\n'.join(output)

    def render(self, name, value, attrs=None, choices=()):
        print 'Inside custom render\n\n'
        if value is None:
            value = []
        final_attrs = self.build_attrs(attrs, name=name)
        output = [format_html('<select multiple="multiple"{}>', 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):
            return data.getlist(name)
        return data.get(name)


class GuideUpdateForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(GuideUpdateForm, self).__init__(*args, **kwargs)
        self.fields['date_modified'].widget = HiddenInput()
        self.fields['point_of_interest'].widget = CustomSelectMultiple()

    class Meta:
        fields = ('name', 'image', 'point_of_interest', 'date_modified', )
        model = Guide

我还尝试更改我的Meta类,

class Meta:
        fields = ('name', 'image', 'point_of_interest', 'date_modified', )
        model = Guide
        widgets = {
            'point_of_interest': SelectMultiple(attrs={'data-img-src': 'www.foo.com'}),
        }

但它仅将属性data-img-src添加到select标记,但不添加到option标记内的所有select标记。

请注意,SelectMultiple类调用renderoptions类的Select方法,该方法进一步调用renderoption方法,该方法没有attrs=None关键字参数。< / p>

2 个答案:

答案 0 :(得分:2)

判断您自己的解决方案,看起来您可能一直在寻找ModelChoiceField

self.fields['point_of_interest'] = forms.ModelChoiceField(widget=CustomSelectMultiple(),
                                                          queryset=poi.objects.all())

queryset参数由&#34;模型对象的QuerySet组成,从中可以派生字段的选项,并且将用于验证用户的选择。&#34;

  

是否会创建一个id元组名称列表?因为我希望选项标记看起来像option value="id">name</option>

我非常确定默认值为id, __str__,其中__str__是模型的字符串表示形式。如果您希望此名称特定于该名称,则可以覆盖此字段并设置label_from_instance

class MyModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.name

答案 1 :(得分:1)

我设法通过将db值传递给choices kwargs来解决这个问题。

from models import poi
class GuideUpdateForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(GuideUpdateForm, self).__init__(*args, **kwargs)
        self.fields['date_modified'].widget = HiddenInput()
        self.fields['point_of_interest'] = forms.ChoiceField(widget=CustomSelectMultiple(), choices=[(i.id,i.name) for i in poi.objects.all()])