Django Forms,使用RadioSelect小部件的ModelChoiceField,由FK分组

时间:2009-03-18 01:04:25

标签: django-forms

挑战,在嵌套<ul></ul>中输出无线电选择,按任务fk分组。

class Category(models.Model):
    # ...

class Task(models.Model):
    # ...
    category = models.ForeignKey(Category)
    # ...

forms.py

class ActivityForm(forms.ModelForm):
    # ...
    task = forms.ModelChoiceField(
        queryset    = Task.objects.all(),
        widget      = RadioSelectGroupedByFK
    )

widgets.py

class RadioFieldRendererGroupedByFK(RadioFieldRenderer):
    """
    An object used by RadioSelect to enable customization of radio widgets.
    """
    #def __init__(self, attrs=None):
        # Need a radio select for each?? Just an Idea.
        #widgets = (RadioSelect(attrs=attrs), RadioSelect(attrs=attrs))
        #super(RadioFieldRendererGroupedByFK, self).__init__(widgets, attrs)

    def render(self):
        """Outputs nested <ul> for this set of radio fields."""
        return mark_safe(
            #### Somehow the crux of the work happens here? but how to get the
            #### right context??
            u'<ul>\n%s\n</ul>' % u'\n'.join(
                [u'<li>%s</li>' % force_unicode(w) for w in self]
            )
        )

class RadioSelectGroupedByFK(forms.RadioSelect):
    renderer = RadioFieldRendererGroupedByFK

非常感谢!!

1 个答案:

答案 0 :(得分:1)

itertools.groupby()非常适合这一点。我假设TaskCategory每个都有一个name属性,您希望它们排序。我不知道Django API,所以你可能想要将排序移动到db查询中,你需要查看widget的属性以找出如何访问任务对象,但这里是基本公式:

from itertools import groupby

# sort first since groupby only groups adjacent items
tasks.sort(key=lambda task: (task.category.name, task.name))

for category, category_tasks in groupby(tasks, key=lambda task: task.category):
  print '%s:' % category.name
  for task in category_tasks:
    print '* %s' % task.name

这应该打印如下列表:

Breakfast foods:
* eggs
* spam
Dinner foods:
* spam
* spam
* spam

HTH