Django accessing formset data
Asked Answered
V

2

11

I'm having difficulty accessing the data submitted through my formset. Here is my code:

Template:

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

    {{ form.as_p }}

    {% endfor %}

    <input type="submit" value="Submit">

</form>

View:

def addMembers(request, id, members):
    if request.user.is_authenticated():
        members = int(members)
        MemberFormSet = formset_factory(MemberForm, extra = members)
        if request.method == 'POST':
            print 'post'
            formset = MemberFormSet(request.POST)
            if formset.is_valid():
                cd = formset.cleaned_data
                for f in formset:
                    first_name = cd.first_name
                    last_name = cd.last_name
                    email = cd.email
                    house = House.objects.get(id = id)
                    member = Member(first_name = first_name, last_name = last_name, email = email, house = house, created_on = timezone.now())
                    member.save()
                return HttpResponseRedirect(reverse('houses:controlPanel'))
        else:
            formset = MemberFormSet()
        return render_to_response('houses/add_members.html', {'formset' : formset}, context_instance = RequestContext(request))
    return HttpResponseRedirect(reverse('allauth.account.views.login'))

I've tried several ways of accessing the data aside from what is currently written including: f['attribute'] cd['attribute'] request.POST['attribute'] formset.cleaned_data['attribute']

I get errors ranging from u"Key 'email' not found in Form" to list indices must be integers, not str

How should I be accessing the data submitted by a formset? Django's documentation fails to give a clear answer to this and searching around I find many different ways but none that have worked yet. Thanks for your help.

Vociferous answered 21/8, 2013 at 16:33 Comment(0)
A
22

cd is a dictionary. Also, you might want to fetch the dictionary values from individual forms rather than the formset

if request.method == 'POST':
    formset = MemberFormSet(request.POST)
    if formset.is_valid():
        for f in formset: 
            cd = f.cleaned_data
            first_name = cd.get('first_name')
            last_name = cd.get('last_name')
            email = cd.get('email')
            house = House.objects.get(id = id)
            member = Member(first_name = first_name, last_name = last_name, email = email, house = house, created_on = timezone.now())
            member.save()
        return HttpResponseRedirect(reverse('houses:controlPanel'))
Archduchy answered 21/8, 2013 at 16:42 Comment(6)
You don't need to check f.is_valid(). A formset isn't valid unless all its form are also valid.Caprifig
any way to check this before is_valid ?Misfeasance
I don't think this could be any more counter intuitive. Thank you for making sense of it all.Wicketkeeper
Am I the only person who thought formset.save() would clean each form and save each form's cleaned data to its respective instance?Wicketkeeper
@PeterDeGlopper In django-1.8.6 it seems your statement is no longer valid. I suspects that In formset <form field>_clean method is not being invoked on individual form.Rather
How do you do this if you are using a forms.BaseFormSet?Textbook
P
0

I think you should be using a model_formsetfactory, or even better, an inlineformset_factory. You are populating models from form data, which is what they are designed for. Get the dirty models from the formset, using commit=False, and add in your House relationship. Something like this:

MemberFormSet = model_formset_factory(Member, extra= members)
if request.method == POST:
    formset = MemberFormSet(request.POST)
    if formset.is_valid():
        house = House.objects.get(id = id)
        models = formset.save(commit=False)
        for member in models:
            member.house = house
            member.save()
        return render(<your data>)
else:
    formset = MemberFormSet()
return render(<your data>)

Note your get() will also throw an exception if the House object doesn't exist. Just a design consideration.

Porett answered 21/8, 2013 at 17:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.