Auto-generate form fields for a Form in django
django, django-forms, python
Solution
Take a look at creating dynamic forms in Django, from b-list.org and uswaretech.com. I've had success using these examples to dynamically create form content from models.
Problem
I have some models and I want to generate a multi-selection form from this data. So the form would contain an entry for each category and the choices would be the skills in that category. models.py ``` class SkillCategory(models.Model): name = models.CharField(max_length=50) class Skill(models.Model): name = models.CharField(max_length=50) category = models.ForeignKey(SkillCategory) ``` Is there a way to auto-generate the form fields? I know I can manually add a 'SkillCategory' entry in the form for each SkillCategory, but the reason to have it as a model is so skills and skillcategories can be edited freely. I want to do something like this: (I tried this, but didn't get it to work, don't remember the exact error...) forms.py ``` class SkillSelectionForm(forms.Form): def __init__(*args, **kwargs): super(SkillSelectionForm, self).__init__(*args, **kwargs) for c in SkillCategory.objects.all(): category_skills = [(pk, s.name) for s in c.skill_set.all()] setattr(self, c.name, forms.MultipleChoiceField(choices=category_skills, widget=forms.CheckboxSelectMultiple)) ``` SOLUTION This creates a form field entry using the SkillCategory.name and assigns choices as those in Skill. field_name/display_name are used to avoid issues with non-ascii category names. forms.py ``` def get_categorized_skills(): skills = {} for s in Skill.objects.values('pk', 'name', 'category__name').order_by('category__name'): if s['category__name'] not in skills.keys(): skills[s['category__name']] = [] skills[s['category__name']].append((s['pk'], s['name'])) return skills class SkillSelectionForm(forms.Form): def __init__(self, *args, **kwargs): super(SkillSelectionForm, self).__init__(*args, **kwargs) skills = get_categorized_skills() for idx, cat in enumerate(skills.keys()): field_name = u'category-{0}'.format(idx) display_name = cat self.fields[field_name] = forms.MultipleChoiceField(choices=skills[cat], widget=forms.CheckboxSelectMultiple, label=display_name) ```