[Answered ]-Django Form 'list' object has no attribute 'iterator'

2đź‘Ť

âś…

This line won’t work:

self.fields['dashboard_select'].queryset = list(chain(article_list, tutorial_list))

The problem does not come from the right part, but from the left. The ModelChoiceField expects queryset to be an actual queryset, not a list.

If you want to supply a list, you should use another field type, namely a ChoiceField. Then you will need to assign the choices. They must be a list of 2-tuples, where first item is the actual value and the second item is the displayed text.

It becomes a bit tricky as the actual value must be a string, or something that can be converted to a string. For instance, we could do something like “article_<pk>” for articles and “tutorial_<pk>” for tutorials.

choices = chain(
    ('article_%d' % obj.pk, str(obj)) for obj in article_list),
    ('tutorial_%d' % obj.pk, str(obj)) for obj in tutorial_list),
)
self.fields['dashboard_select'].choices = choices

You may replace the str(obj) with whatever is a sensible way to display the object to the user.

And then when your form is validated you will get the value, which you should parse back:

from django.core.exceptions import ObjectDoesNotExist, ValidationError

# on your form class
def clean_dashboard_select(self):
    data = self.cleaned_data['dashboard_select'] # will be, eg: "article_42"
    try:
        typename, value = data.split('_')
        pk = int(value)
    except ValueError:
        raise ValidationError('cannot understand %s' % data)
    try:
        if typename == 'article':
            return Article.objects.get(pk=pk)
        if typename == 'tutorial':
            return Tutorial.objects.get(pk=pk)
    except ObjectDoesNotExist:
        raise ValidationError('No %s with pk %d' % (typename, pk))
    raise ValidationError('Never heard of type %s' % typename)

Edit (from comment) — to add section groups, change the choices like this:

choices = (
    ('Articles', tuple(('article_%d' % obj.pk, str(obj)) for obj in article_list)),
    ('Tutorials', tuple(('tutorial_%d' % obj.pk, str(obj)) for obj in tutorial_list)),
)
👤spectras

Leave a comment