Comment puis-je créer plusieurs boutons de soumission sous forme de django?

156

J'ai un formulaire avec une entrée pour l'e-mail et deux boutons d'envoi pour m'abonner et me désabonner de la newsletter:

<form action="" method="post">
{{ form_newsletter }}
<input type="submit" name="newsletter_sub" value="Subscribe" />
<input type="submit" name="newsletter_unsub" value="Unsubscribe" />
</form>

J'ai aussi la forme de classe:

class NewsletterForm(forms.ModelForm):
    class Meta:
        model = Newsletter
        fields = ('email',)

Je dois écrire ma propre méthode clean_email et j'ai besoin de savoir par quel bouton le formulaire a été soumis. Mais la valeur des boutons d'envoi n'est pas dans le self.cleaned_datadictionnaire. Pourrais-je obtenir les valeurs des boutons autrement?

veena
la source

Réponses:

97

Vous pouvez utiliser self.datadans la clean_emailméthode pour accéder aux données POST avant validation. Il doit contenir une touche appelée newsletter_subou newsletter_unsubselon le bouton qui a été enfoncé.

# in the context of a django.forms form

def clean(self):
    if 'newsletter_sub' in self.data:
        # do subscribe
    elif 'newsletter_unsub' in self.data:
        # do unsubscribe
Ayman Hourieh
la source
4
pouvez-vous donner un exemple annoté? ça aiderait vraiment
Jharwood
9
Je ne pense pas que ce cleansoit vraiment le bon endroit pour faire de la logique au niveau du modèle. C'est spécifiquement pour nettoyer un formulaire et trouver tout ValidationErrors qui couvre plusieurs entrées. La réponse de Sven est plus dans la bonne direction, mais pas nécessairement la meilleure réponse
Patrick
8
Risque de sécurité! L'utilisation de données de formulaire pour apporter des modifications à la base de données avant que le formulaire n'ait été validé est dangereuse.
Quant Metropolis
1
Vous souhaiterez peut-être exécuter différents types de validation en fonction du bouton sur lequel vous avez appuyé. Dans ce cas, il n'y a pas d'impact «Sécurité».
sureshvv
230

Par exemple:

if 'newsletter_sub' in request.POST:
    # do subscribe
elif 'newsletter_unsub' in request.POST:
    # do unsubscribe
Damon Abdiel
la source
1
La requête est-elle disponible dans les méthodes de validation clean_xxx?
sureshvv
Dans quelle méthode cela devrait-il aller?
Jon McClung
1
@JonMcClung Inside def post(self, request, *args, **kwargs).
A. Kali
23

Vous pouvez aussi faire comme ça,

 <form method='POST'>
    {{form1.as_p}}
    <button type="submit" name="btnform1">Save Changes</button>
    </form>
    <form method='POST'>
    {{form2.as_p}}
    <button type="submit" name="btnform2">Save Changes</button>
    </form>

CODE

if request.method=='POST' and 'btnform1' in request.POST:
    do something...
if request.method=='POST' and 'btnform2' in request.POST:
    do something...

la source
form1.as_p quand utiliser ceci ?? dans les vues, tout en vérifiant la validité du formulaire, j'aimerais pouvoir faire ... form1.is_valid () puis faire ceci, form2.is_valid () faire ceci ..
tilaprimera
5

C'est une vieille question maintenant, néanmoins j'ai eu le même problème et j'ai trouvé une solution qui fonctionne pour moi: j'ai écrit MultiRedirectMixin.

from django.http import HttpResponseRedirect

class MultiRedirectMixin(object):
    """
    A mixin that supports submit-specific success redirection.
     Either specify one success_url, or provide dict with names of 
     submit actions given in template as keys
     Example: 
       In template:
         <input type="submit" name="create_new" value="Create"/>
         <input type="submit" name="delete" value="Delete"/>
       View:
         MyMultiSubmitView(MultiRedirectMixin, forms.FormView):
             success_urls = {"create_new": reverse_lazy('create'),
                               "delete": reverse_lazy('delete')}
    """
    success_urls = {}  

    def form_valid(self, form):
        """ Form is valid: Pick the url and redirect.
        """

        for name in self.success_urls:
            if name in form.data:
                self.success_url = self.success_urls[name]
                break

        return HttpResponseRedirect(self.get_success_url())

    def get_success_url(self):
        """
        Returns the supplied success URL.
        """
        if self.success_url:
            # Forcing possible reverse_lazy evaluation
            url = force_text(self.success_url)
        else:
            raise ImproperlyConfigured(
                _("No URL to redirect to. Provide a success_url."))
        return url
Sven
la source
Où et comment allez-vous utiliser MultiRedirectMixin exactement? Veuillez élaborer avec un exemple.
Saurav Kumar
4

une URL vers la même vue! ainsi!

urls.py

url(r'^$', views.landing.as_view(), name = 'landing'),

views.py

class landing(View):
        template_name = '/home.html'
        form_class1 = forms.pynamehere1
        form_class2 = forms.pynamehere2
            def get(self, request):
                form1 = self.form_class1(None)
                form2 = self.form_class2(None)
                return render(request, self.template_name, { 'register':form1, 'login':form2,})

             def post(self, request):
                 if request.method=='POST' and 'htmlsubmitbutton1' in request.POST:
                        ## do what ever you want to do for first function ####
                 if request.method=='POST' and 'htmlsubmitbutton2' in request.POST:
                         ## do what ever you want to do for second function ####
                        ## return def post###  
                 return render(request, self.template_name, {'form':form,})
/home.html
    <!-- #### form 1 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ register.as_p }}
    <button type="submit" name="htmlsubmitbutton1">Login</button>
    </form>
    <!--#### form 2 #### -->
    <form action="" method="POST" >
      {% csrf_token %}
      {{ login.as_p }}
    <button type="submit" name="htmlsubmitbutton2">Login</button>
    </form>
chrisroker0
la source