Plusieurs ModelForm dans une page

bouton submit

Le problème exposé dans ce sujet a été résolu.

Bonjour, alors j'ai un problème qui va surement vous paraitre bête, mais j'ai une page qui contient plusieurs ModelForm avec chacun un bouton submit, du coup mon problème est que lorsque je remplis le formulaire et que je clic sur le bouton ça me créer bien mon objet dans la bonne table de ma base donnée mais en gros il active aussi tout les autres formulaires de page ce qui est un peu gênant… je ne comprend pas tellement pourquoi il me semble pourtant avoir bien fais même si je pense aussi que mon code peut être grandement amélioré. Donc je viens demander votre aide afin que quel qu'un puisse m'expliquer mon erreur pour que je puisse savoir ce qui cloche car pour l'instant je ne vois pas d’où viens ce problème.

voici mon code:

la vues:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def Experimentform(request):
    form = ExpForm(request.POST or None)  
    Siform = SixcForm(request.POST or None)
    kbform = KbForm(request.POST or None) 
    Othform = OtherForm(request.POST or None)
    Optform = OpticsForm(request.POST or None) 
    context =  {
            "form" : form,
            "Siform" : Siform,
            "kbform" : kbform,
            "Othform" : Othform,
            "Optform" : Optform
    }    

    if form.is_valid():
        instance = form.save(commit=False)
        instance.save()
        form = ExpForm()

    if Siform.is_valid():
        instance = Siform.save(commit=False)
        instance.save()
        Siform = SixcForm()

    if kbform.is_valid():
        instance = kbform.save(commit=False)
        instance.save()
        kbform = KbForm()

    if Othform.is_valid():
        instance = Othform.save(commit=False)
        instance.save()
        Othform = OtherForm()

    if Optform.is_valid():
        instance = Optform.save(commit=False)
        instance.save()
        Optform = OpticsForm()


    return render(request, 'data/experiment.html', context )

le html :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{% block jumbotron %}
<div class="jumbotron">

    <div class ="row">
        <div class ="col-xs-3">
            <form method ="POST" action ="">{% csrf_token %}
                {{Siform|crispy}}
                <input class="btn btn-primary" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="">{% csrf_token %}
                {{kbform|crispy}}
                <input class="btn btn-primary" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="">{% csrf_token %}
                {{Optform|crispy}}
                <input class="btn btn-primary" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="">{% csrf_token %}
                {{Othform|crispy}}
                <input class="btn btn-primary" type="submit" value="Add"/>
            <form/>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class ="row">
    <h1>Experiment</h1>
    <div class ="col-md-8">
        <form method ="POST" action ="">{% csrf_token %}
            {{form|crispy}}
            <input class="btn btn-primary" type="submit" value="Send to database"/>

        <form/>
    </div>
</div>
{% endblock %}

Merci d'avance pour votre aide !

+0 -0

si tu as la même action partout, c'est normal que ça fasse des choses bizarrement.

Il faut que chaque form soit lié à la bonne url donc il faut que son attribut action soit correctement initialisé avec un truc style <form method="POST" action="{% url 'ton-module:ton-action' %}">

+0 -0

D'accord du coup si j'ai bien compris faudrait que je crées une fonction dans mon views.py pour chaque ModelForm, et que je crées une url pour chacune un peut dans ce style là ?

1
2
3
4
5
6
7
urlpatterns = patterns('data.views',
        url(r'^form$','Experimentform'),
        url(r'^form$','SixcForm'),
        url(r'^form$','OpticsForm'),
        url(r'^form$','KbForm'),
        url(r'^form$','OtherForm'),
    ) 

sauf qu'il faut que toutes les regex soient différentes du style :

1
2
3
4
5
6
7
urlpatterns = patterns('data.views',
        url(r'^formexperiment$','Experimentform'),
        url(r'^formsixc$','SixcForm'),
        url(r'^formoptics$','OpticsForm'),
        url(r'^formkb$','KbForm'),
        url(r'^formother$','OtherForm'),
    ) 

Bonjours , Désolé de répondre autant de temps après mais du coup j'ai pus me replancher sur le problèmes, du coup j'ai bien fais une URL pour chaque action, j'ai revus la method dans views.py, j'ai toujours c'est satanés boutons qui s'activent en même temps et je comprend toujours pas pourquoi il me semble pourtant avoirs bien fait… je vous mets les modifications que j'ai effectué si vous voulez les voir.( les 5,4,3,2,1 sont les noms de mes butons je sais que c'est pas très explicite mais bon c’était pour les tests ne me jeté pas de pierre ^^ )

l'HTML:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block jumbotron %}
<div class="jumbotron">

    <div class ="row">
        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'sixcform' %}">{% csrf_token %}
                {{Siform|crispy}}
                <input class="btn btn-primary" name="1" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'kbform' %}">{% csrf_token %}
                {{kbform|crispy}}
                <input class="btn btn-primary" name="2" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'opticsform' %}">{% csrf_token %}
                {{Optform|crispy}}
                <input class="btn btn-primary" name="3" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'otherform' %}">{% csrf_token %}
                {{Othform|crispy}}
                <input class="btn btn-primary" name="4" type="submit" value="Add"/>
            <form/>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class ="row">
    <h1>Experiment</h1>
    <div class ="col-md-8">
        <form method ="POST" action ="{% url 'Expform' %}">{% csrf_token %}
            {{form|crispy}}
            <input class="btn btn-primary" name="5" type="submit" value="Send to database"/>

        <form/>
    </div>
</div>
{% endblock %}

Les urls :

1
2
3
4
5
6
7
8
9
urlpatterns = patterns('data.views',
    url(r'^index$', 'home',name = 'search_results'),
    url(r'^form$','Experimentform',name = 'Expform'),
    url(r'^formSixc$','Experimentform',name = 'sixcform'),
    url(r'^formKb$','Experimentform',name = 'kbform'),
    url(r'^formOptics$','Experimentform',name = 'opticsform'),
    url(r'^formOther$','Experimentform',name = 'otherform'),
    url(r'^view/(?P<pk>[\w-]+)/$', ExperimentView.as_view(),name = 'viewExp'),
    ) 

et le view.py :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def Experimentform(request):
    form = ExpForm(request.POST or None)  
    Siform = SixcForm(request.POST or None)
    kbform = KbForm(request.POST or None) 
    Othform = OtherForm(request.POST or None)
    Optform = OpticsForm(request.POST or None) 
    context =  {
            "form" : form,
            "Siform" : Siform,
            "kbform" : kbform,
            "Othform" : Othform,
            "Optform" : Optform
    }    
    if request.method =='POST':
        if form.is_valid() and Siform.is_valid() and kbform.is_valid() and Othform.is_valid() and Optform.is_valid() :
            if '5' in request.POST:
                instance = form.save(commit=False)
                instance.save()
            elif '1' in request.POST:
                instance = Siform.save(commit=False)
                instance.save()
            elif '2' in request.POST:
                instance = kbform.save(commit=False)
                instance.save()
            elif '3' in request.POST: 
                instance = Othform.save(commit=False)
                instance.save()
            elif '4' in request.POST:  
                instance = Optform.save(commit=False)
                instance.save()
            form = ExpForm()
            Siform = SixcForm()
            kbform = KbForm()
            Othform = OtherForm()
            Optform = OpticsForm()

Salut

Un bouton submit dans un fom envoie uniquement le form dans lequel il se trouve (voire rine du tout, pas même le bouton si le form est vide). Donc déjà, ta condition ligne 15 ne me semble pas une bonne idée : dans ce cas précis, tu n'auras qu'un formulaire valide à chaque fois.

Ensuite je te conseille de faire une fonction par formulaire si tu fais plutot des vues basées sur les fonctions. En l'occurence dans ce cas, tu as fais pointer tes 5 URL sur la même fonctions dans ton urls.py, ce qui n'est pas forcément une bonne pratique, tu complexifies inutilement ton fichier d'url qui est déjà amené à grossir assez rapidement… Donc si tu veux tout regrouper dans une même fonction, une seule url est suffisante, mais on préferera séparer en général.

+0 -0

Ah donc tu veux dire que lorsque je clic sur le boutons d'un des formulaire pour envoyer l'objet dans ma base de données, si les autres formulaire on des champs qui s'activent en me disant que tel champs est requis c'est normal même si j'ai pas cliqué sur leur bouton ?

+0 -0

Ah donc tu veux dire que lorsque je clic sur le boutons d'un des formulaire pour envoyer l'objet dans ma base de données, si les autres formulaire on des champs qui s'activent en me disant que tel champs est requis c'est normal même si j'ai pas cliqué sur leur bouton ?

Myrens

Ce comportement ne m'étonne pas du tout. Tu essaies de valider (ligne 15) tous les formulaires alors que tu n'en as envoyé qu'un seul (tu n'as les données que d'un form dans request.POST même si tu as rempli d'autre champs dans ta page html). donc forcément tu dois avoir 4 formulaires sur 5 qui sont invalides avec des erreurs du type "Le champ xxx est requis".

C'est comme si tu passais un objet Form vide au 4 formulaires surlesquels tu n'as pas cliqués et que tu essayais de les valider : et évidement si des champs ne sont pas remplis (données non présentes dans POST) ben ça valide pas.

Est ce que tu as compris ?

+0 -0

Oui je vois très bien le soucie ligne 15, le problème c'est qu'aux début j'avais fais une fonction par formulaire et au final j'avais des soucies avec des formulaires qui s’affichaient pas (les 4 du haut, alors que celui du bas de la page s'affichait très bien alors que j'avais procédé de la même manière avec chacun son url et tout, et puis si je cliqué sur un bouton le formulaire du bas disparaissait et le premier formulaire en haut a gauche apparaissaient )

Du coup j'ai tout fais dans une fonction et j'avais tout mes formulaires d'affiché avec chacun son bouton et lorsque je validé le formulaire les données etaient envoyé dans les bonne tables et que le seul soucie c'est que cliquer sur un bouton active le submit de tout les formulaires. donc je comprend bien du le soucie ligne 15 de vérifier tout les formulaires mais bon je vois pas trop comment ne pas le faire et les vérifier un par un.

Si tu peux nous montrer ce que tu avais fait au début ? Je pense que tu avais juste un problème d'initialisation.

Si tu veux garder ta fonction actuelle, il faudrait plus faire quelque chose dans ce genre la (mais ca serait tout de même mieux dans des fonctions séparés : là tu ne fais pratiquement rien et ta vue est déjà complexe):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def Experimentform(request):
    form = ExpForm(request.POST or None)  
    Siform = SixcForm(request.POST or None)
    kbform = KbForm(request.POST or None) 
    Othform = OtherForm(request.POST or None)
    Optform = OpticsForm(request.POST or None) 
    context =  {
            "form" : form,
            "Siform" : Siform,
            "kbform" : kbform,
            "Othform" : Othform,
            "Optform" : Optform
    }    
    if request.method =='POST':
        if '5' in request.POST:
            if form.is_valid():
                instance = form.save(commit=False)
                instance.save()
        elif '1' in request.POST:
            if Siform.is_valid():
                instance = Siform.save(commit=False)
                instance.save()
        elif '2' in request.POST:
            if kbform.is_valid():
                instance = kbform.save(commit=False)
                instance.save()
        elif '3' in request.POST: 
            if Othform.is_valid():
                instance = Othform.save(commit=False)
                instance.save()
        elif '4' in request.POST:
            if Optform.is_valid():
                instance = Optform.save(commit=False)
                instance.save()
        form = ExpForm()
        Siform = SixcForm()
        kbform = KbForm()
        Othform = OtherForm()
        Optform = OpticsForm()

Alors avant j'avais fais ça:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def Experimentform(request):
    form = ExpForm(request.POST or None)  
    context =  {
            "form" : form
    }    
    if form.is_valid():
        instance = form.save(commit=False)
        instance.save()
        form = ExpForm()
    return render(request, 'data/experiment.html', context )

def Sform(request):
    Siform = SixcForm(request.POST or None)  
    context =  {
            "Siform" : Siform
    }    
    if Siform.is_valid():
        instance = Siform.save(commit=False)
        instance.save()
        Siform = SixcForm()
    return render(request, 'data/experiment.html', context )

def Kform(request):
    kbform = KbForm(request.POST or None)  
    context =  {
            "kbform" : kbform,
    }    
    if kbform.is_valid():
        instance = kbform.save(commit=False)
        instance.save()
        kbform = KbForm()
    return render(request, 'data/experiment.html', context )

def Otform(request):
    Othform = OtherForm(request.POST or None)  
    context =  {
            "Othform" : Othform,
    }    
    if Othform.is_valid():
        instance = Othform.save(commit=False)
        instance.save()
        Othform = OtherForm()
    return render(request, 'data/experiment.html', context )

def Opform(request):
    Optform = OpticsForm(request.POST or None)  
    context =  {
            "Optform" : Opticsform,
    }    
    if Optform.is_valid():
        instance = Optform.save(commit=False)
        instance.save()
        Optform = Form()
    return render(request, 'data/experiment.html', context )

et les Urls étaient :

1
2
3
4
5
6
7
8
9
urlpatterns = patterns('data.views',
    url(r'^index$', 'home',name = 'search_results'),
    url(r'^form$','Experimentform',name = 'Expform'),
    url(r'^formSixc$','Sform',name = 'sixcform'),
    url(r'^formKb$','Kform',name = 'kbform'),
    url(r'^formOptics$','Otform',name = 'opticsform'),
    url(r'^formOther$','Opform',name = 'otherform'),
    url(r'^view/(?P<pk>[\w-]+)/$', ExperimentView.as_view(),name = 'viewExp'),
    ) 

L'html lui n'as pas changé ^^

+0 -0

Ah d'accord, ben ton problème avant, c'est juste qu'il faut tout le temps initialiser tes 5 formulaires avant le rendu :

1
2
3
4
5
6
7
return render(request, 'data/experiment.html', {
        'form': ExpForm(),
        'Siform': SixcForm(),
        'kbform': KbForm(),
        'Othform': OtherForm(),
        'Optform': OpticsForm(),
})

Bien sur en modifiant le formulaire concerné dans chaque fonction par exemple. Et après tu peux regoruper pour éviter de dupliquer du code aussi.

Pour des pages assez complexes avec du code repeté dans ce genre là (surtout que y a pas de traitemente extra), les class-based views permettent de mieux organisées le code, bien que les développeurs python/Django sont pas forcément tous d'accord sur ce dernier point. En tout cas, c'est important de commencer par des fonctions pour bien comprendre les mécaniques de Django.

Si jamais, tu peux aller voir le blog de Sam&Max [NSFW] tu trouveras pas mal d'article sur le développement sous Django et c'est tout en français ;)

Nan, je te montre mais il ne faut pas replacer ce code tel quel. C'est juste pour te montrer que tu dois avoir dans ton context une instance de chaque form de la page. donc tu dois initialiser ton context avec tous les forms pour que les objets existe dans ton template.

Tu auras donc par exemple:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def Opform(request):
    Optform = OpticsForm(request.POST or None)
    if request.method == 'POST':
        if Optform.is_valid():
            instance = Optform.save(commit=False)
            instance.save()
            Optform = Form()

    context =  {
        'form': ExpForm(),
        'Siform': SixcForm(),
        'kbform': KbForm(),
        'Othform': OtherForm(),
        'Optform': Optform,
    }
    return render(request, 'data/experiment.html', context)

Merci beaucoup j'ai compris ! les formulaires s'affiche bien, le seul soucie c'est que maintenant c'est toujours le même qui s'active mais bon ça dois être au niveau des Urls le problème je penses, Merci beaucoup !

Myrens

En effet, si comme tu l'as dit, tu as gardé le même html, tu as la même url en action de tous tes formulaires ;)

Je parlais de cette HTML c'est pour ça ^^

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block jumbotron %}
<div class="jumbotron">

    <div class ="row">
        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'sixcform' %}">{% csrf_token %}
                {{Siform|crispy}}
                <input class="btn btn-primary" name="1" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'kbform' %}">{% csrf_token %}
                {{kbform|crispy}}
                <input class="btn btn-primary" name="2" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'opticsform' %}">{% csrf_token %}
                {{Optform|crispy}}
                <input class="btn btn-primary" name="3" type="submit" value="Add"/>
            <form/>
        </div>


        <div class ="col-xs-3">
            <form method ="POST" action ="{% url 'otherform' %}">{% csrf_token %}
                {{Othform|crispy}}
                <input class="btn btn-primary" name="4" type="submit" value="Add"/>
            <form/>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class ="row">
    <h1>Experiment</h1>
    <div class ="col-md-8">
        <form method ="POST" action ="{% url 'Expform' %}">{% csrf_token %}
            {{form|crispy}}
            <input class="btn btn-primary" name="5" type="submit" value="Send to database"/>

        <form/>
    </div>
</div>
{% endblock %}
+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte