2011-02-09 14 views
15

Questo è più o meno quello che sto cercando di fare:Django: come aggiungere un modulo aggiuntivo a un formset dopo che è stato costruito?

def post(request): 
    VehicleFormSet = formset_factory(StaffVehicleForm) 
    if request.method == 'POST': 
     vehicle_formset = VehicleFormSet(request.POST) 
     if 'add_vehicle' in request.POST: 
      if vehicle_formset.is_valid(): 
       form_count = vehicle_formset.total_form_count() 
       vehicle_formset.forms.append(vehicle_formset._construct_form(form_count)) 

In sostanza, se un utente fa clic sul pulsante "Aggiungi" e il loro ingresso è valido, voglio aggiungere un'altra forma vuota per il formset, e nascondere il precedente.

Il problema con il codice precedente è che non riesco a capire come aumentare total_form_count(). Il modo in cui lo ho ora, funzionerà una volta, e quindi se lo preme di nuovo, non accadrà nulla, presumibilmente perché lo form_count è lo stesso. Non mi piace anche chiamare _construct_form e fare affidamento sulla parte interna.

risposta

3

Lo faccio utilizzando javascript. Dal momento che il formset rende tre campi di gestione

<input type="hidden" id="id_TOTAL_FORMS" value="1" name="TOTAL_FORMS"> 
<input type="hidden" id="id_INITIAL_FORMS" value="1" name="INITIAL_FORMS">. 
<input type="hidden" id="id_MAX_NUM_FORMS" name="MAX_NUM_FORMS"> 

è possibile utilizzare javascript per incrementare il valore id_TOTAL_FORMS, e basta aggiungere nei campi aggiuntivi. Quindi creo il mio fieldset in questo modo:

VehicleFormSet = modelformset_factory(StaffVehicleForm, extra = 0, max_num = None) 

La cosa complicata è creare i campi del modulo aggiuntivo in javascript. Di solito uso AJAX per recuperare una nuova riga da una vista personalizzata.

+4

l'attributo '' empty_form' su BaseFormSet' potrebbe essere utile qui. http://docs.djangoproject.com/en/1.2/topics/forms/formsets/#empty-form "restituisce un'istanza di modulo con un prefisso di' __prefix__' per un utilizzo più semplice nelle forme dinamiche con JavaScript "Puoi mantenerlo come un modello da clonare credo. –

+3

Non voglio farlo in JS però ... – mpen

+0

Oh buon consiglio Reiner Gerecke! La prossima volta la userò :-) – Humphrey

8
class RequiredFormSet(BaseFormSet): 
    def add_form(self, **kwargs): 
     # add the form 
     tfc = self.total_form_count() 
     self.forms.append(self._construct_form(tfc, **kwargs)) 
     self.forms[tfc].is_bound = False 

     # make data mutable 
     self.data = self.data.copy() 

     # increase hidden form counts 
     total_count_name = '%s-%s' % (self.management_form.prefix, TOTAL_FORM_COUNT) 
     initial_count_name = '%s-%s' % (self.management_form.prefix, INITIAL_FORM_COUNT) 
     self.data[total_count_name] = self.management_form.cleaned_data[TOTAL_FORM_COUNT] + 1 
     self.data[initial_count_name] = self.management_form.cleaned_data[INITIAL_FORM_COUNT] + 1 

    def add_fields(self, form, index): 
     super(RequiredFormSet, self).add_fields(form, index) 
     form.empty_permitted = False 

Questo lo farà. Ci sono volute solo 7 ore per capirlo. E ancora non so perché ho bisogno di .is_bound = False per rendere i valori iniziali non rovinati.

+0

is_bound dovrebbe sempre essere falso a meno che il modulo è destinato a POST presentata (o ottenere) i dati. – Humphrey

+0

@Humphrey: Sì ... ed è così. L'intero formset è. Non voglio però che i moduli vuoti, ancora da aggiungere, siano vincolati. – mpen

+0

@mpen Come dovrei chiamare questo metodo e da dove posso ottenere TOTAL_FORM_COUNT e altre variabili. – CrazyGeek

0

Per i posteri ecco un altro modo che funziona senza JS (o accanto a JS) e che non richiede una conoscenza approfondita dei metodi di formset. Invece, puoi semplicemente ispezionare i dati POST e regolarli come se JS avesse fatto del lavoro lato client. Quanto segue fa in modo che ci sia sempre (almeno) una forma vuota alla fine del formset:

def hsview(request): 
    HS_formset = formset_factory(HSTestForm, extra=3) 
    prefix='XYZZY' 
    testinpost, empty = 'key', '' # field in the form and its default/empty value 
    extra=3 

# I prefer to do the short init of unbound forms first, so I invert the usual test ... 
    if request.method != 'POST': 

     formset = HS_formset(prefix=prefix) 
    else: 
     # process POSTed forms data. 
     # pull all relevant things out of POST data, because POST itself is not mutable 
     # (it doesn't matter if prefix allows in extraneous items) 

     data = { k:v for k,v in request.POST.items() if k.startswith(prefix) } 

     #if there are no spare empty forms, tell it we want another form, in place of or extra to client-side JS 
     #don't want to crash if unvalidated POST data is nbg so catch all ... 
     try: 
      n = int(data[ prefix + '-TOTAL_FORMS']) 
      test = '{}-{}-{}'.format(prefix, n-1, testinpost) 
      #print(test) 
      test = data.get(test, empty) 
     except Exception: 
      test = 'bleagh' 
      # log the error if it matters enough ... 
     if test != empty: 
      data[ prefix + '-TOTAL_FORMS'] = n + 1 

     # now the usual formset processing ... 
     formset = HS_formset(data, prefix=prefix) 
     # other_form = OtherForm(request.POST) 
     if formset.is_valid(): 
      ...    
Problemi correlati