1

I have two forms in two different tabs in the same template. The models of the forms are connected through a foreign key.

When I'm trying to save each form independently having a submit button for each form, but unfortunately the two forms are trying to save data again, even I push only one submit button.

Views.py

def input(request):
    my_demographics = DemographicForm(request.POST or None)
    my_diagnosis = DiagnosisForm(request.POST or None)

    context = RequestContext(request)
    if request.method == 'POST':
        submitted = request.POST.get('form_id', '')

        if submitted == 'demographics':
            # Get the Form1 instance
            my_demographics = DemographicForm(request.POST)
            if my_demographics.is_valid():
                my_demographics_object= my_demographics.save()
                my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id})


        elif submitted == 'diagnosis':
            # Get the Form2 instance
            my_diagnosis = DiagnosisForm(request.POST)
            if my_diagnosis.is_valid():
                my_diagnosis.save()

        else:
            raise ValueError('No form specified !')


return render_to_response('input.html', {'frm':my_demographics, 'frm_d': my_diagnosis}, context)

input.html

<div class="tab-content">

    <!-- Tab panes -->
    <form class="tab-pane fade in active" id="demographics" method="post" >
        <input type="hidden" name="form_id" value="demographics">
        {%crispy frm%}
    </form>
    <form class="tab-pane fade" id="diagnosis" method="post">
         <input type="hidden" name="form_id" value="diagnosis">
        {%crispy frm_d%}
    </form>
</div>
zinon
  • 3,630
  • 8
  • 53
  • 91
  • possible duplicate of [Proper way to handle multiple forms on one page in Django](http://stackoverflow.com/questions/1395807/proper-way-to-handle-multiple-forms-on-one-page-in-django) – madzohan Oct 24 '14 at 15:03
  • Not really, the OP want to submit both of them with the same form, and the linked question is about handling multiple submit in the same page ! – e-nouri Oct 24 '14 at 15:06
  • I think you've misread the question - "... trying to save each form independently having a submit button for each form ..." – Brandon Oct 24 '14 at 15:07

2 Answers2

5

First add an hidden input in each of your forms, which will specify which form is posted:

<div class="tab-content">

    <!-- Tab panes -->
    <form class="tab-pane fade in active" id="demographics" method="post" >
        <input type="hidden" name="form_id" value="demographics"> 
        {%crispy frm%}
    </form>
    <form class="tab-pane fade" id="diagnosis" method="post">
        <input type="hidden" name="form_id" value="diagnosis"> 
        {%crispy frm_d%}
    </form>
</div>

Then in your view, check which form is posted and only save this form.

edit:

def input(request):
    context = RequestContext(request)
    if request.method == 'POST':
        submitted = request.POST.get('form_id', '')

        if submitted == 'demographics':
            # Get the Form1 instance
            my_demographics = DemographicForm(request.POST)
            if my_demographics.is_valid():
                my_demographics_object= my_demographics.save()
                my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id})
             else:
                my_diagnosis=DiagnosisForm()

        elif submitted == 'diagnosis':
            # Get the Form2 instance
            my_diagnosis = DiagnosisForm(request.POST)
            if my_diagnosis.is_valid():
                my_diagnosis.save()
                # here you should redirect

            my_demographics = DemographicForm()

        else:
            raise ValueError('No form specified !')

    else:
        my_demographics = DemographicForm()
        my_diagnosis = DiagnosisForm()

    return render_to_response(
        'input.html', 
         {'frm':my_demographics, 'frm_d': my_diagnosis}, 
         context
         )
bruno desthuilliers
  • 68,994
  • 6
  • 72
  • 93
  • How do I check in view which form is posted? – zinon Oct 24 '14 at 15:12
  • `form_id = request.POST.get('form_id')` request.POST is a dictionary, and thus has the static method .get() available. If the value is not in the dictionary, `None` will be returned. – Brandon Oct 24 '14 at 15:13
  • `request.POST.get("form_id")` will tell you. The point is to use the same name for both inputs. – bruno desthuilliers Oct 24 '14 at 15:14
  • `if 'one_sub' in request.POST: # do something elif 'two_sub' in request.POST: # do something else` – madzohan Oct 24 '14 at 15:15
  • @brunodesthuilliers Exactly. @zinon, then you would check for the value... `if form_id == 'demographics':` – Brandon Oct 24 '14 at 15:15
  • 1
    @madzohan That would only check for the presence of the key in the request.POST dictionary, not return its value. Both hidden fields are named identically. The value of the key is what's needed to determine the correct logic in the view. – Brandon Oct 24 '14 at 15:17
  • @Brandon I edit my `views.py` and `input.html` template, but my problem insists! Any idea? – zinon Oct 24 '14 at 18:22
  • @zinon: please first fix you view's code indentation. – bruno desthuilliers Oct 24 '14 at 18:35
  • @brunodesthuilliers OK, I fixed it! – zinon Oct 24 '14 at 18:47
  • @zinon: your updated snippet should JustWork(tm). You state that the problem is that "the two forms are trying to save data again" but what is the symptom exactly ? – bruno desthuilliers Oct 24 '14 at 19:03
  • @brunodesthuilliers The problem is when I'm trying to save data from 2nd form `DiagnosisForm` I get an error on the first form `DemographicForm`that the field `patient_id` is required. – zinon Oct 24 '14 at 19:10
  • @brunodesthuilliers Even though that the first form saved a minute earlier. – zinon Oct 24 '14 at 19:11
  • @brunodesthuilliers The data are stored OK in the database but the first form is raising the `field required` error, ever though I do not push the first's form submit button! – zinon Oct 24 '14 at 19:18
  • @zinon: ok, it's a validation error on the first form when you submit the second one. I don't have a playground Django project at hand ATM so I can't validate my hypothesis but I think the problem might come from your view's first two lines where you pass `request.POST` to both forms. See my edited answer for a saner code. Now what puzzles me is that without an explicit call to `is.valid()` on the first form you shouldn't have this problem. If you still have the problem with this code, it will be time to add a couple print statements or run the code thru the debugger. – bruno desthuilliers Oct 24 '14 at 19:35
  • @brunodesthuilliers Thanks! That's it! Is there any way to keep information on the first form, but not save it again? Just for reference? – zinon Oct 24 '14 at 20:06
  • @zinon only one form (the HTTML forms I mean) is posted. If you want to keep the fist form's data, you either have to render it again (as hidden fields) in the second, or store it in a session. – bruno desthuilliers Oct 25 '14 at 09:02
  • @brunodesthuilliers Thank you! Which is the easier option? Do you have any simple example please? – zinon Oct 25 '14 at 14:29
  • @zinon each solution has it's drawbacks, but as far as I'm concerned I'd rather go for the session. You'll find all relevant informations in the official doc https://docs.djangoproject.com/en/1.7/topics/http/sessions/ – bruno desthuilliers Oct 27 '14 at 12:47
0

The view will have the input names that were inside the form submitted only, that is how you now, so you can add a hidden field and check for its value, if form1, or form2 then you know witch one have being submitted !

if request.POST:
    # Get the form submitted
    submitted = request.POST.get('form_name', '')

    if submitted == 'form1'
        # Get the Form1 instance
        form = Form1Model(request.POST)

    elif submitted == 'form2'
        # Get the Form2 instance
        form = Form2Model(request.POST)
    else:
         raise ValueError('No form specified !')

    # Validate the form
    if form.is_valid():
        # If the form is valid save it
        if form.save():
            # correct data entry
            messages.info(
                request,
                _(u"Fichier copié sur le DHS, mise à jour en cours ...")
            )
        else:
            # Can't save the form
            messages.warning(
                request,
                _(u"Un problème est survenu pendant l'enregistrement "
                  u"des données, merci de réessayer plus tard.")
            )
    else:
        # Form is not valid, show feedback to the user
        messages.error(
            request,
            _(u"Merci de corriger les erreurs suivantes.")
        )
else:
    # Empty forms this is the first call
    form1 = Form1Model()
    form2 = Form2Model()

    # Disclaimer
    messages.warning(
        request,
        _(u"L'interface web sera inaccessible durant la mise à jour.")
    )
e-nouri
  • 2,338
  • 1
  • 16
  • 30
  • No, they don't. The view doesn't know which form has been submitted. It only knows a POST occurred. The form needs to be identified by a parameter, which the view can use to decide when processing the post. – Brandon Oct 24 '14 at 15:05
  • Yes they have, if you hit the submit inside a form it will only post the forms input, this is a basic HTML specification. – e-nouri Oct 24 '14 at 15:07
  • And how exactly does the view know that? – Brandon Oct 24 '14 at 15:07
  • @Brandon Can you give me a simple example please? – zinon Oct 24 '14 at 15:09
  • The view will have the input names that were inside the form submitted only, that is how you now, so you can add a hidden field and check for its value, if form1, or form2 then you know witch one have being submitted ! – e-nouri Oct 24 '14 at 15:09
  • Updated the response after the clarifications. – e-nouri Oct 24 '14 at 15:10
  • That's exactly what I stated previously. The form classes and view have absolutely no idea what form was submitted unless you specifically tell them. – Brandon Oct 24 '14 at 15:10
  • you can use the form fields to check, if the forms are different, but yes I do agree with you on that. – e-nouri Oct 24 '14 at 15:13
  • If I have only one form, how to render two forms in the template? I want to have `DiagnosisForm({'patient': my_demographics_object.patient_id })` in the second form. – zinon Oct 24 '14 at 17:06
  • You can just add the same for 2 times to the lookup dictonary – e-nouri Oct 25 '14 at 05:10