【问题标题】:Django ModelChoiceField optgroup tagDjango ModelChoiceField optgroup 标签
【发布时间】:2013-02-19 01:40:14
【问题描述】:

如何在 ModelChoiceField optgroup 标签中设置?

这是一个例子:

models.py

class Link(models.Model):
    config = models.ForeignKey(Config)
    name = models.URLField(u'Name', null=True, max_length=50)
    gateway = models.IPAddressField(u'Gateway', null=True)
    weight = models.IntegerField(u'Weight', null=True)
    description = models.TextField(u'Description', blank=True)

def __unicode__(self):
    return self.name

forms.py

class LinkForm(ModelForm):
    config = ModelChoiceField(queryset=Config.objects.all(), empty_label="Choose a link",widget=GroupedSelect())

class Meta:
    model = Link

我想像这样呈现我的 ChoiceField:

example.html

<select id="id_config" name="config">
    <option selected="selected" value="">Choose a link</option>
    <optgroup label="Configuration" >
        <option value="8">Address: 192.168.1.202/255.255.255.0 </option>
        <option value="9">Address: 192.168.1.240/255.255.255.0 </option>
        <option value="10">Address: 192.168.3.1/255.255.255.0 </option>
    </optgroup>
</select>

**更新**

我这样解决了我的问题:

class GroupedSelect(Select):
    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{0}>', flatatt(final_attrs))]
        for index, option_gp in enumerate(self.choices):
            if index == 0:
                option_value = smart_unicode(option_gp[0])
                option_label = smart_unicode(option_gp[1])
                output.append(u'<option value="%s">%s</option>' %  (escape(option_value), escape(option_label)))
                output.append('<optgroup label = "Configuration">')
            elif index!=0 and index <= len(self.choices):
                option_value = smart_unicode(option_gp[0])
                option_label = smart_unicode(option_gp[1])
                output.append(u'<option value="%s">%s</option>' % (escape(option_value), escape(option_label)))          
        output.append(u'</optgroup>')
        output.append(u'</select>')
        return mark_safe('\n'.join(output))

【问题讨论】:

标签: python django django-templates django-forms


【解决方案1】:

这是一个很好的sn-p:

使用可选 Optgroups 选择字段并选择小部件: http://djangosnippets.org/snippets/200/

【讨论】:

  • 是的,这真的很棒。我按照这些说明... Tnxx
【解决方案2】:

您不需要创建任何自定义字段,Django 已经完成了这项工作,只需传递格式正确的选项:

MEDIA_CHOICES = (
 ('Audio', (
   ('vinyl', 'Vinyl'),
   ('cd', 'CD'),
  )
 ),
 ('Video', (
   ('vhs', 'VHS Tape'),
   ('dvd', 'DVD'),
  )
 ),
)

【讨论】:

  • 如果有人想用 ChoiceField 做多层嵌套,我在我的博客上写了一个方法:mostthingsweb.com/2015/04/…
  • 但这适用于ChoiceField,而不是ModelChoiceField,对吧?
  • 他要求提供 ModelChoiceField,但这并没有解决。答案错误。
【解决方案3】:

@Stefan Manastirliu 答案的扩展,可与django-categories 一起使用。 (缺点是下面的get_tree_data() 函数只允许一级)。与bootstrap multiselect 等javascript 插件结合使用,您可以获得 等多选功能

Models.py

from categories.models import CategoryBase
class SampleCategory(CategoryBase):
    class Meta:
        verbose_name_plural = 'sample categories'

class SampleProfile(models.Model):
    categories = models.ManyToManyField('myapp.SampleCategory')

forms.py

from myapp.models import SampleCategory

    def get_tree_data():
        def rectree(toplevel):
            children_list_of_tuples = list()
            if toplevel.children.active():
                for child in toplevel.children.active():
                    children_list_of_tuples.append(tuple((child.id,child.name)))

            return children_list_of_tuples

        data = list()
        t = SampleCategory.objects.filter(active=True).filter(level=0)
        for toplevel in t:
            childrens = rectree(toplevel)
            data.append(
                tuple(
                    (
                        toplevel.name,
                        tuple(
                            childrens
                            )
                        ) 
                    )
            )
        return tuple(data)

class SampleProfileForm(forms.ModelForm):
    categories = forms.MultipleChoiceField(choices=get_tree_data())
    class Meta:
        model = SampleProfile

【讨论】:

    【解决方案4】:

    ModelChoiceField 使用ModelChoiceIterator 将查询集转换为选项列表。 您可以轻松地覆盖此类以引入组。 以下是按国家/地区对城市进行分组的示例:

    from itertools import groupby
    from django.forms.models import ModelChoiceField, ModelChoiceIterator
    from .models import City
    
    class CityChoiceIterator(ModelChoiceIterator):
        def __iter__(self):
            queryset = self.queryset.select_related('country').order_by('country__name', 'name')
            groups = groupby(queryset, key=lambda x: x.country)
            for country, cities in groups:
                yield [
                    country.name,
                    [
                        (city.id, city.name)
                        for city in cities
                    ]
                ]
    
    class CityChoiceField(ModelChoiceField):
        iterator = CityChoiceIterator
    
        def __init__(self, *args, **kwargs):
            super().__init__(City.objects.all(), *args, **kwargs)
    

    注意:我没有时间检查此技术是否与 Django 3.1 中引入的新 ModelChoiceIteratorValue 兼容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-23
      • 2013-11-29
      • 1970-01-01
      • 2018-03-10
      • 1970-01-01
      相关资源
      最近更新 更多