How to process multiple form data at once in views.py?

Hey, I want to create simple form where admin can submit multiple data for multiple user at one just using 1 submit button. First, here is my models

class GeeksUser(models.Model):
    name = models.CharField(max_length=10)
    age = models.IntegerField()

class GeeksArticle(models.Model):
    geeksuser = models.ForeignKey(GeeksUser, on_delete=models.CASCADE)
    title = models.CharField(max_length=20)
    topic = models.CharField(max_length=10)

my form.html

<form method="POST" enctype="multipart/form-data"> 
    {% csrf_token %}
    {% for author in authors %}
        <div class='userForm'>
            <span>{{ author.name }}</span>
            {{ form.title }}
            {{ form.topic }}
            <input type="hidden" name="by" value="{{ author.name }}">
        </div>
    {% endfor %}
    <br>
    <input type="submit">
</form> 

and my views, where I process the data

    authors = GeeksUser.objects.all()

    if response.method == 'POST':
        form = GeeksArticleForm(response.POST)
    
        if form.is_valid():
            title = form.cleaned_data['title']
            topic = form.cleaned_data['topic']
            by = form.cleaned_data['by']

            guser = GeeksUser.objects.get(name=by)
            narticle = GeeksArticle(title=title, topic=topic, geeksuser=guser)
            narticle.save()
        context = {
            'form' : form,
            'authors' : authors,
        }
        return render(response, "home.html", context)
    else:
        form = GeeksArticleForm()
    context = {
        'form' : form,
        'authors' : authors,
    }
    return render(response, "form.html", context)

Now, the form work, but not the way I expected it to work.
When I tested the form, only the latest user’s form is sent to the database. For example if in my User model I have 3 user, so forms.html will display all three user’s form.
I have filled in each user’s field form, and submit the form. but only the latest users’s field is being sent to the database.
I believe the way I handle the data from views.py is wrong here, but I cannot figure out the correct way to process multiple user form data at once in views.py.

That’s all, thank you

This is the purpose of formsets. (Handling multiple instances of the same form.)

Formsets may take a little getting used to - I’ve also been recommending this thread (and the links in it) to help get started.

I thought formset only used for multiple form?
Because what I’m creating is multiple user form, so each user only got 1 form.
But I guess I haven’t really look into formset, alright I’ll look into it. Thank you :smiley:

It’s for multiple instances of the same form. Precisely what you’re doing here.

I have modified my form to use formset like this:

def geeksView(response):
    authors = GeeksUser.objects.all()
    StoryFormSet = formset_factory(StoryForm)
    formset = StoryFormSet()

    if response.method == 'POST':
        formset = StoryFormSet(response.POST)
    
        if formset.is_valid():
            for form in formset:
                title = form.cleaned_data['title']
                topic = form.cleaned_data['topic']
                by = form.cleaned_data['by']

            guser = GeeksUser.objects.get(name=by)
            narticle = GeeksArticle(title=title, topic=topic, geeksuser=guser)
            narticle.save()
        context = {
            'form' : formset,
            'authors' : authors,
        }
        return render(response, "home.html", context)
    else:
        formset = StoryFormSet()
    context = {
        'formset' : formset,
        'authors' : authors,
    }
    return render(response, "home.html", context)

and my template like this :

<form method="POST" enctype="multipart/form-data"> 
    {% csrf_token %}
    {{ formset.management_form.as_p }}
    <div>
        {% for form in formset.forms %}
            {% for author in authors %}
                <span>{{ author.name }}</span>
                {{ form.as_p }}
            {% endfor %}
        {% endfor %}
    </div>
    <br>
    <input type="submit">
</form> 

But before I talk about the data processing, the way these forms are displayed to the page is not what I expected. Each form still has the same ID and name. I suppose that is because the way I loop these form is by using {% for author in authors %}, because if I use extra=2 attribute inside the form declaration in views, there will be additional form with different namd and id.
But if I don’t use {% for author in authors %}, I don’t know how to display form for each different user.

This should be a ModelFormset with a queryset parameter to identify the instances being edited. Each form within the formset gets created with an association with an individual instance of the model in the queryset.

You can then render the entire formset as {{ formset }}. Or, you can still render individual forms as for form in formset.forms, but you do not then iterate the authors within that, because each form will be for a different author.

1 Like

Alright, I’ll look into it.
Thank you