1

Note: Django/Python beginner, hope this question is clear

I need to create a form where multiple instances of a model can be edited at once in a single form, and be submitted at the same time.

For instance, I have two models, Invite and Guest, where multiple Guests can be associated with a single Invite. I need a single form where I'm able to edit particular details of all Guests attached to the invite, submit at the same time, and save to the database.

I've seen a few suggestions about using crispy-forms, but haven't managed to get it working.

I've created a form that provides certain inputs:

from django import forms
from app.models import Guest


class ExtraForm(forms.ModelForm):
    diet = forms.CharField(max_length=128, required=False)
    transport = forms.BooleanField(initial=False)

    # An inline class to provide additional information on the form.
    class Meta:
        # Provide an association between the ModelForm and a model
        model = Guest
        fields = ('diet', 'transport')

My view consists of:

def extra_view(request, code):
    invite = get_invite(code)
    # Get the context from the request.
    context = RequestContext(request)

    # Get just guests labelled as attending
    guests_attending = invite.guest_set.filter(attending=True)

    if request.method == 'POST':
        form = ExtraForm(request.POST)

        print(form.data)

        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            # form.save(commit=True)

            print(form)

            return render(request, 'weddingapp/confirm.html', {
                'invite': invite,
            })
        else:
            # The supplied form contained errors - just print them to the terminal for now
            print form.errors
    else:
        # # If the request was not a POST, display the form to enter details.
        GuestForm = ExtraForm()

    return render_to_response('weddingapp/extra.html', 
           {'GuestForm': GuestForm, 'invite': invite, 'guests_attending': guests_attending}, context)

And finally, my form:

<form id="extra_form" method="post" action="{% url 'weddingapp:extra' invite.code %}">

    {% csrf_token %}

    {% for guest in guests_attending %}
        <fieldset class="form-group">
            <h3>Form for {{ guest.guest_name }}</h3>
            {% for field in GuestForm.visible_fields %}
                {{ field.errors }}

                <div>
                    {{ field.help_text }}
                    {{ field }}
                </div>
            {% endfor %}
        </fieldset>
    {% endfor %}

    {{ form.management_form }}
    <table>
        {% for form in form %}
            {{ form }}
        {% endfor %}
    </table>

    <input type="submit" name="submit" value="Submit"/>
</form>

Any advice

1

1 Answer 1

4

You need to use a FormSet, in particular a ModelFormSet:

...
GuestFormSet = modelformset_factory(Guest, form=ExtraForm)

in your view you can use it as a normal form:

formset = GuestFormSet(data=request.POST)

if formset.is_valid():
  formset.save()

and in your template:

   <form method="post" action="">
     {{ formset.management_form }}
       <table>
         {% for form in formset %}
           {{ form }}
         {% endfor %}
       </table>
   </form>

tip: you can avoid the avoid this boilerplate

if request.method == 'POST':
    form = ExtraForm(request.POST)

    print(form.data)

    # Have we been provided with a valid form?
    if form.is_valid():

with a simple shortcut:

form = ExtraForm(data=request.POST or None)
if form.is_valid():
  ...
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.