Domanda Django: come aggiungere un form extra a un formset dopo che è stato costruito?


Questo è più o meno quello che sto cercando di fare:

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

Fondamentalmente, se un utente fa clic sul pulsante "Aggiungi" e la loro voce è valida, voglio aggiungere un altro modulo vuoto al formset e nascondere quello precedente.

Il problema con il codice sopra è che non riesco a capire come aumentare total_form_count(). Il modo in cui lo ho ora, funzionerà una voltae poi se lo premi di nuovo, non accadrà nulla, presumibilmente perché form_count è la stessa. Anche a me non piace telefonare _construct_form e basandosi sugli interni.


16
2018-02-09 21:24


origine


risposte:


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 .is_bound = False per rendere i valori iniziali non rovinati.


9
2018-02-11 00:29



Lo faccio usando javascript. Poiché il formset esegue il rendering di 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">

puoi utilizzare javascript per incrementare il valore id_TOTAL_FORMS e aggiungere semplicemente i 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 in più in javascript. Di solito uso AJAX per recuperare una nuova riga da una vista personalizzata.


3
2018-02-09 23:06



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 si assicura che ci sia sempre (almeno) un modulo vuoto 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(): 
            ...            

0
2017-10-19 12:59