2009-12-06 7 views
36

J'ai fait une belle forme, et une grande fonction 'add' compliquée pour la manipuler. Il commence comme ça ...Django modifier le formulaire basé sur le formulaire d'ajout?

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

Maintenant, je ne veux pas vraiment reproduire tout ce que la fonctionnalité dans la méthode edit(), donc je pensais edit pourrait utiliser exactement le même modèle, et peut-être juste ajouter un champ à id le formulaire de sorte que la fonction add savait ce qu'il était en train d'éditer. Mais il y a quelques problèmes avec ce

  1. Où puis-je mettre article.id dans la add func? Il devrait être après form.save parce que c'est là que l'article est créé, mais il ne l'atteindrait jamais, parce que le formulaire est invalide en raison de contraintes uniques (sauf si l'utilisateur a tout modifié). Je peux simplement supprimer le contrôle is_valid, mais form.save échoue à la place.
  2. Si le formulaire en réalité est invalide, le champ I ajouté dynamiquement dans la fonction d'édition n'est pas conservé.

Alors, comment faire face à cela?

Répondre

88

Si vous étendez votre formulaire à partir d'un ModelForm, utilisez l'argument de mot-clé instance. Ici, nous passons soit un instance existant ou un nouveau, selon que nous modifions ou ajoutons un article existant. Dans les deux cas, le champ author est défini sur l'instance, donc commit=False n'est pas requis. Notez également que je suppose que seul l'auteur peut éditer ses propres articles, d'où la réponse 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 
    }) 

Et dans votre urls.py:

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

Le même edit vue est utilisé pour les ajouts et modifications, mais seulement le modèle modifier url passe un identifiant à la vue. Pour faire ce travail bien avec votre formulaire, vous aurez besoin d'omettre le champ de la forme author:

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

Oui, il est un 'ModelForm'. J'avais besoin de 'commit = False' pour d'autres raisons. Un article est composé de tout un tas de choses (y compris des relations m2m). Je ne * pense * pas qu'il voulait travailler avec 'instance'. Je vais essayer cela. – mpen

+1

Dans ce cas, je suggérerais de mettre les relations m2m (et al) d'enregistrement/validation dans le formulaire au lieu de la vue ... soit de surcharger la méthode save, soit éventuellement, de regarder dans les formsets. Je suppose que cela dépend du contexte de ce que vous travaillez avec ... –

+5

Un exemple parfait! Merci! J'ai appris plus que juste la solution à cette question. – hobbes3

1

Vous pouvez avoir un champ ID caché dans le formulaire et pour le modifier, il sera passé avec le formulaire pour ajouter un formulaire que vous pouvez définir dans req.POST par ex.

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

et passer que formData pour former

Questions connexes