2009-07-18 11 views
7

Il modello suggested per l'elaborazione di un modulo in una vista sembra eccessivamente complesso e non DRY a me:Alternativa alla scheda di elaborazione del modulo django?

def contact(request): 
    if request.method == 'POST': # If the form has been submitted... 
     form = ContactForm(request.POST) # A form bound to the POST data 
     if form.is_valid(): # All validation rules pass 
      # Process the data in form.cleaned_data 
      # ... 
      return HttpResponseRedirect('/thanks/') # Redirect after POST 
    else: 
     form = ContactForm() # An unbound form 

    return render_to_response('contact.html', { 
     'form': form, 
    }) 

che è un sacco di condizionali, si ripete la costruzione ContactForm(), e l'intero blocco si ripete in tutto il mondo una vista deve elaborare un modulo. Non c'è un modo migliore per farlo?

+0

Django ha viste generiche da diversi anni. Questa domanda e tutte le risposte che vedo sono obsolete. Vedi: https://docs.djopoproject.com/en/1.9/ref/class-based-views/generic-editing/ – guettli

risposta

10

È possibile evitare la ripetizione, ovviamente. Principalmente, è necessario passare come argomenti la classe del nome di modulo e modello da utilizzare, un callable per elaborare i dati puliti quando viene inviato un modulo valido e una destinazione per il reindirizzamento dopo tale elaborazione; Inoltre, è necessario un piccolo codice aggiuntivo per chiamare la classe del modulo una sola volta, per produrre un modulo associato o non associato e gestirlo correttamente. Vale a dire:

def process_any_form(request, 
        form_class, template_file_name, 
        process_data_callable, redirect_destination): 

    form = form_class(request.POST if request.method == 'POST' else None) 

    if form.is_bound and form.is_valid(): 
     process_data_callable(form.cleaned_data) 
     return HttpResponseRedirect(redirect_destination) 

    return render_to_response(template_file_name, {'form': form}) 
+2

Funziona. Se il modello vuole qualcosa di più della semplice 'forma', è necessario ampliare l'elenco degli argomenti per includere, ad esempio, un hash di valori. –

+0

s/hash/dict /, ma, sì, buona idea: puoi passare in un dtt semi-pre-popolato per il contesto, e usare dict (d, form = form) come contesto per il rendering, questo rende soluzione ancora più generale. –

2

Il modo di elaborazione delle forme di elaborazione combina due problemi: presentare un modulo per modificare ed elaborare i risultati. È possibile suddividere questo in due metodi, che introdurranno alcune duplicazioni sotto forma di identiche chiamate render_to_response(). Nel momento in cui l'hai refactored, è possibile che finisca con qualcosa che è meno leggibile rispetto al modulo a metodo singolo sopra.

Quando guardo il metodo boilerplate, non vedo la duplicazione. I due usi di ContactForm() sono nettamente diversi. I due condizionali mi sembrano mostrare in modo abbastanza pulito le transizioni di stato coinvolte nell'elaborazione di un modulo (presentare un modulo vuoto, accettare le submission fino a quando uno è valido, process-and-redirect).

0

Si potrebbe scrivere una funzione che gestisca i condizionali per tutte le forme. Si potrebbe fare questo passando in una funzione specifica a quella forma dopo "is_valid", come ad esempio:

def FormHandler(request, CleaningFunction, redirecturl): 
    if request.method = 'POST': 
     if request.method == 'POST': # If the form has been submitted... 
      form = ContactForm(request.POST) # A form bound to the POST data 
      if form.is_valid(): # All validation rules pass 
       CleaningFunction(form) # Process the data in form.cleaned_data 
       return HttpResponseRedirect('/thanks/') # Redirect after POST 
    else: 
     form = ContactForm() # An unbound form 
    return form 

Poi si potrebbe chiamare FormHandler dal vostro punto di vista. Nota che questo non è testato e potrebbe contenere errori.

1

gestore generico di Alex mi ha battuto ad esso, ma FWIW abbiamo tendono verso una versione meno generica del suo suggerimento:

def contact(request): 
    post_data = request.POST if request.method == 'POST' else None 
    form = ContactForm(post_data) 
    if request.method == 'POST': 
     # perform normal validation checking, etc 

    return render_to_response('contact.html', { 
     'form': form, 
     }) 

Se post_data è None, allora la forma viene creata un'istanza come sconfinata. In caso contrario, l'elaborazione rilegata continua normalmente. Evita una costruzione duplicata di ContactForm, ma sono d'accordo con la risposta di Dave che la costruzione duplicata non mi infastidisce come un duplicato proprio perché i parametri di costruzione sono diversi.

1

Mi sono così stancato di questo che ho scritto le mie viste generiche per gestirlo. Nel processo, ho scoperto che django already has underdocumented generic views per l'elaborazione di moduli. Sono analoghi abbastanza diretti delle viste generiche documentate, ma accettano moduli e fondamentalmente seguono lo stesso modello che hai usato nel tuo esempio. In definitiva, li ho trovati troppo rigidi e stupidi per il mio uso (non voglio una vista create_or_update, non voglio trattare queste due azioni separatamente)

Modifica: Non ti è piaciuta la risposta di Fragsworth, che punti alla stessa cosa di cui sto parlando, presumo che anche tu non sia come il mio. Ecco un esempio di come funziona.

# in urls.py 
urlpatterns += patterns("", 
    (u'^...$', 'django.views.generic.create_update.update', { 
     'form_class': ContactForm }) 
) 

ContactForm deve avere un metodo save(), e questo è dove la logica di elaborazione dei moduli va.

0

È possibile bypassare il modulo moduli di django e farlo semplicemente alla vecchia maniera, si ottiene una maggiore flessibilità senza troppa perdita IMHO.

L'ultima volta che ho guardato le forme di django è stato un po 'di tempo fa, non so se le cose sono cambiate, ma per esempio, non ti permette di costruire una forma in stile Ajax; almeno non facilmente.

6

Hai ragione potrebbe essere meglio, qui è un'alternativa migliore (ma continuate a leggere):

def contact(request): 
    form = ContactForm(request.POST or None) # A form bound to the POST data 
    if form.is_valid(): # All validation rules pass 
     # Process the data in form.cleaned_data 
     # ... 
     return HttpResponseRedirect('/thanks/') # Redirect after POST 

    return render_to_response('contact.html', { 
     'form': form, 
    }) 

Questo frammento proviene da un discorso chiamato Advanced Django Form Usage da DjangoCon11.

Si noti che questo elaborerà un modulo vuoto come valido (anche prima dell'invio) se tutti i campi sono facoltativi e non si utilizza la protezione CSRF. Quindi per eliminare tale rischio, è meglio usare questo:

def contact(request): 
    form = ContactForm(request.POST or None) # A form bound to the POST data 
    if request.method == 'POST' and form.is_valid(): # All validation rules pass 
     # Process the data in form.cleaned_data 
     # ... 
     return HttpResponseRedirect('/thanks/') # Redirect after POST 

    return render_to_response('contact.html', { 
     'form': form, 
    }) 
Problemi correlati