2009-09-11 11 views
8

Tengo algunos modelos y deseo generar un formulario de selección múltiple a partir de estos datos. Entonces el formulario contendría una entrada para cada categoría y las opciones serían las habilidades en esa categoría.Generación automática de campos de formulario para un formulario en django

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) 

¿Hay una manera de generar auto-los campos del formulario? Sé que puedo agregar manualmente una entrada 'SkillCategory' en el formulario para cada SkillCategory, pero la razón para tenerlo como modelo es que las habilidades y categorías de destrezas se pueden editar libremente.

quiero hacer algo como esto: (He intentado esto, pero no conseguir que funcione, no recuerdo el error exacto ...)

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)) 

SOLUCIÓN

Esto crea una entrada en el campo de formulario mediante el Sk illCategory.name y asigna elecciones como aquellas en Skill. field_name/display_name se utilizan para evitar problemas con los nombres de categoría no ascii.

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) 

Respuesta

1

Tome un vistazo a la creación de formularios dinámicos en Django, de b-list.org y uswaretech.com. He tenido éxito usando estos ejemplos para crear dinámicamente contenido de formulario a partir de modelos.

+0

Gracias, esto me señaló en la dirección correcta, ver mi texto de arriba para mi solución final. – monkut

1

Lo que queremos es un formset. Esto le dará un conjunto de filas, cada una de las cuales se correlaciona con una Habilidad específica.

Véase el Formset documentation y la página específica en la generación de formsets for models.

+0

Gracias, esto parece ser el enfoque correcto, sólo hay que volver a pensar en el problema desde esta perspectiva. – monkut

2

Bien, así que no puede establecer campos como ese en forms.Form, por razones que se harán aparentes cuando vea DeclarativeFieldsMetaclass, la metaclase de forms.Form (pero no de forms.BaseForm). Una solución que puede ser excesiva en su caso, sino un ejemplo de cómo la construcción de forma dinámica se puede hacer, es algo como esto:

base_fields = [ 
    forms.MultipleChoiceField(choices=[ 
     (pk, s.name) for s in c.skill_set.all() 
    ]) for c in SkillCategory.objects.all() 
] 
SkillSelectionForm = type('SkillSelectionForm', (forms.BaseForm,), {'base_fields': base_fields}) 
+0

Original, pero parece viable. Gracias por la referencia del código! – monkut

Cuestiones relacionadas