tags:

views:

2131

answers:

1

The challenge, output a radio select in nested <ul></ul>, grouped by the task fk.

ie.

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

Best thanks!!

+1  A: 

itertools.groupby() is perfect for this. I'll assume that Task and Category each have a name attribute you want them sorted by. I don't know the Django APIs, so you'll probably want to move sorting into the db query, and you'll need to look at the widget's attributes to figure out how to access the task objects, but here's the basic formula:

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

This should print a list like:

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

HTH

Matt Good