Skip to main content
 首页 » 编程设计

python之Django 表单和 ModelChoiceField : Add HTML optgroup element to specific objects in QuerySet

2025年05月04日30pander-it

class CreateCourseForm(ModelForm): 
        category = forms.ModelChoiceField( 
            queryset=Category.objects.all(), 
            empty_label="", 
            #widget=CustomCourseWidget() 
        ) 
 
    class Meta: 
        model = Course 
        fields = ('title', 'description', 'category') 
 
    def __init__(self, *args, **kwargs): 
        super(CreateCourseForm, self).__init__(*args, **kwargs) 
        self.fields['category'].widget.attrs['class'] = 'chzn-select' 
        self.fields['category'].widget.attrs['data-placeholder'] = u'Please select one' 

使用上面的代码,我得到了一个选择框,其中列出了所有类别对象。我想做的是添加一个

<optgroup>VALUE</optgroup>  

特定类别对象的 HTML 元素(具有 Category.parent == null 的对象)。

有人知道怎么做吗?非常感谢!

PS:我已经尝试将 QuerySet 转换为 Choices-Set(例如 http://dealingit.wordpress.com/2009/10/26/django-tip-showing-optgroup-in-a-modelform/ ),它可以很好地呈现 HTML - 直到我尝试将结果保存到数据库中,但出现不匹配(ValueError)。

请您参考如下方法:

这是我目前的解决方案。这可能是一个肮脏的修复,但它工作正常:-)

class CustomCourseWidget(forms.Select): 
    #http://djangosnippets.org/snippets/200/ 
    def render(self, name, value, attrs=None, choices=()): 
        from django.utils.html import escape 
        from django.utils.encoding import smart_unicode 
        from django.forms.util import flatatt 
 
        if value is None: 
            value = '' 
        final_attrs = self.build_attrs(attrs, name=name) 
        output = [u'<select%s>' % flatatt(final_attrs)] 
        output.append(u'<option value=""></option>') # Empty line for default text 
        str_value = smart_unicode(value) 
        optgroup_open = False 
        for group in self.choices: 
            option_value = smart_unicode(group[0]) 
            option_label = smart_unicode(group[1]) 
            if not ">" in option_label and optgroup_open == True: 
                output.append(u'</optgroup>') 
                optgroup_open = False 
            if not ">" in option_label and optgroup_open == False: 
                output.append(u'<optgroup label="%s">' % escape(option_label)) 
                optgroup_open = True 
            if " > " in option_label: 
                #optgroup_open = True 
                selected_html = (option_value == str_value) and u' selected="selected"' or '' 
                output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label.split(" > ")[1]))) 
 
        output.append(u'</select>') 
        return mark_safe(u'\n'.join(output))