Opened 9 years ago

Last modified 9 years ago

#24541 closed Cleanup/optimization

save_new_objects in ModelFromsets do not handle intitial data — at Version 5

Reported by: Johannes Maron Owned by: nobody
Component: Documentation Version: dev
Severity: Normal Keywords: modelformset
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Johannes Maron)

If you create a ModelFormSet and pass initial data for some forms, the forms are evaluated as has_changed False.
All in all that is true, but it has the the side effect that the forms in the formset don't get saved, tho they contain data.

The error is here:
https://github.com/django/django/blob/master/django/forms/models.py#L777-L778

It should not only be checked for has_changed but also for initial data.

Change History (5)

comment:1 by Tim Graham, 9 years ago

Resolution: invalid
Status: newclosed

You should use initial forms instead of extra forms if you require those populated forms to be submitted. Changing the behavior to validate and save unchanged extra forms would be backwards incompatible. Feel free to reopen if I missed something.

comment:2 by Johannes Maron, 9 years ago

Resolution: invalid
Status: closednew

That does not work for ModelFormSets as the pop initial to initial_extra and only except existing objects using the Queryset.
There currently is no way to create objects using a ModelFormSet with initial data.

I get your point, about compatibility, but you should decide if this odd behavior is a bug or a feature. Personally it feels like a bug. Especially as Model and regular form sets handle initial data so differently. There is no consistent behavior nor any documentation about this.

comment:3 by Tim Graham, 9 years ago

Easy pickings: unset

I had no trouble with this view:

from django.forms.models import modelformset_factory

def test_view(request):
    qs = Poll.objects.none()
    PollFormSet = modelformset_factory(Poll, fields='__all__')
    if request.method == 'POST':
        formset = PollFormSet(request.POST, queryset=qs)
        if formset.is_valid():
            formset.save()
    else:
        formset = PollFormSet(queryset=qs, initial=[
            {'question': 'initial', 'pub_date': timezone.now()}])
    return render(request, 'polls/manage.html', {'formset': formset})

Can you provide a snippet that demonstrates your problem?

comment:4 by Johannes Maron, 9 years ago

As I said:
It does not work if your submitted are not yet created and you can't pass a queryset.

from django.forms.models import modelformset_factory

def test_view(request):
    qs = Poll.objects.none()
    PollFormSet = modelformset_factory(Poll, fields='__all__')
    if request.method == 'POST':
        formset = PollFormSet(request.POST, initial=[{'question': 'Foo'}, {'question': 'Bar'}])
        if formset.is_valid():
            obj_list = formset.save()
            assert len(obj_list) == 2
    else:
        formset = PollFormSet(queryset=qs, initial=[
            {'question': 'initial', 'pub_date': timezone.now()}])
    return render(request, 'polls/manage.html', {'formset': formset})

This will fail.

Last edited 9 years ago by Johannes Maron (previous) (diff)

comment:5 by Johannes Maron, 9 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top