2009-12-06 18 views
36

Ho creato una bella forma e una complicata funzione di "add" per gestirla. Si inizia così ...Modulo di modifica di Django basato sul modulo di aggiunta?

def add(req): 
    if req.method == 'POST': 
     form = ArticleForm(req.POST) 
     if form.is_valid(): 
      article = form.save(commit=False) 
      article.author = req.user 
      # more processing ... 

Ora io non voglio davvero duplicare tutto ciò che la funzionalità nel metodo edit(), così ho pensato edit potrebbe utilizzare lo stesso esatto modello, e forse basta aggiungere un campo a id il modulo in modo che la funzione add sapesse cosa stava modificando. Ma ci sono un paio di problemi con questo

  1. Dove vorrei impostare article.id nel add func? Dovrebbe essere dopo form.save perché è lì che viene creato l'articolo, ma non lo raggiungerebbe mai, perché il modulo non è valido a causa di vincoli univoci (a meno che l'utente non abbia modificato tutto). Posso semplicemente rimuovere il controllo is_valid, ma al posto di form.save esito negativo.
  2. Se il modulo in realtà è non valido, il campo I aggiunto dinamicamente nella funzione di modifica non viene mantenuto.

Quindi, come faccio a gestire questo?

risposta

88

Se si estende il modulo da un ModelForm, utilizzare l'argomento instance parola chiave. Qui passiamo uno instance esistente o uno nuovo, a seconda se stiamo modificando o aggiungendo un articolo esistente. In entrambi i casi il campo author è impostato sull'istanza, quindi commit=False non è richiesto. Nota anche che sto assumendo che solo l'autore possa modificare i propri articoli, da qui la risposta HttpResponseForbidden.

from django.http import HttpResponseForbidden 
from django.shortcuts import get_object_or_404, redirect, render, reverse 


@login_required 
def edit(request, id=None, template_name='article_edit_template.html'): 
    if id: 
     article = get_object_or_404(Article, pk=id) 
     if article.author != request.user: 
      return HttpResponseForbidden() 
    else: 
     article = Article(author=request.user) 

    form = ArticleForm(request.POST or None, instance=article) 
    if request.POST and form.is_valid(): 
     form.save() 

     # Save was successful, so redirect to another page 
     redirect_url = reverse(article_save_success) 
     return redirect(redirect_url) 

    return render(request, template_name, { 
     'form': form 
    }) 

E nel tuo urls.py:

(r'^article/new/$', views.edit, {}, 'article_new'), 
(r'^article/edit/(?P<id>\d+)/$', views.edit, {}, 'article_edit'), 

La stessa edit vista viene utilizzato sia per aggiunte e modifiche, ma solo il modello Modifica URL passa un id alla vista. Per fare bene questo lavoro con il modulo è necessario omettere il campo author dalla forma:

class ArticleForm(forms.ModelForm): 
    class Meta: 
     model = Article 
     exclude = ('author',) 
+0

Sì, è un 'ModelForm'. Avevo bisogno di 'commit = False' per altri motivi. Un articolo è composto da un sacco di cose (incluse alcune relazioni m2m). Non penso * che volesse lavorare con 'instance'. Darò questa prova però. – mpen

+1

In tal caso, suggerirei di inserire le relazioni m2m (e così via) nel salvataggio/convalida nel modulo anziché nella vista ... o sovrascrive il metodo di salvataggio o, eventualmente, guarda nei formulari. Immagino che dipenda dal contesto in cui stai lavorando ... –

+5

Ottimo e completo esempio! Grazie! Ho imparato più che la giusta soluzione a questa domanda. – hobbes3

1

È possibile avere il campo ID nascosto nel modulo e per il modulo di modifica verrà passato con il modulo per il modulo di aggiunta è possibile impostarlo in req.POST ad es.

formData = req.POST.copy() 
formData['id'] = getNewID() 

e passare che formdata per formare

Problemi correlati