2009-09-11 2 views
8

Ho alcuni modelli e voglio generare un modulo di selezione multipla da questi dati. Quindi il modulo conterrebbe una voce per ogni categoria e le scelte sarebbero le abilità in quella categoria.Genera automaticamente campi modulo per un modulo in 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) 

Esiste un modo per generare automaticamente i campi del modulo? So che posso aggiungere manualmente una voce 'SkillCategory' nel modulo per ogni SkillCategory, ma il motivo per averlo come modello è che le abilità e le categorie di abilità possono essere modificate liberamente.

voglio fare qualcosa di simile: (ho provato questo, ma non sono riuscito a farlo funzionare, non ricordo l'errore esatto ...)

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

SOLUZIONE

Questo crea una voce di campo modulo utilizzando il Sk illCategory.name e assegna le scelte come quelle in Abilità. field_name/display_name vengono utilizzati per evitare problemi con nomi di categorie non-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) 

risposta

1

Date un'occhiata a creare forme dinamiche di Django, da b-list.org e uswaretech.com. Ho avuto successo usando questi esempi per creare dinamicamente il contenuto del modulo dai modelli.

+0

Grazie, questo mi ha indirizzato nella giusta direzione, vedere la mia modifica sopra per la mia soluzione finale. – monkut

1

quello che vuoi è un Formset. Questo ti darà una serie di file, ognuna delle quali si dirige su una specifica Abilità.

Vedere Formset documentation e la pagina specificatamente sulla generazione formsets for models.

+0

Grazie, questo sembra essere l'approccio giusto, ho solo bisogno di ripensare il problema da questa prospettiva. – monkut

2

Ok, quindi non è possibile impostare campi come questo su forms.Form, per ragioni che diventeranno evidenti quando vedete DeclarativeFieldsMetaclass, il metaclasse di forms.Form (ma non di forms.BaseForm). Una soluzione che può essere eccessivo nel vostro caso, ma un esempio di come dinamica costruzione forma si può fare, è qualcosa di simile:

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

Funky, ma sembra funzionante. Grazie per il codice di riferimento! – monkut