Opened 7 years ago

Last modified 6 years ago

#27560 closed Bug

Formset.save() crashes for model with foreign key to concrete base model — at Version 2

Reported by: Lorenzo Peña Owned by: nobody
Component: Forms Version: 1.9
Severity: Normal Keywords: formset inline_formset inline_formsetfactory
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Lorenzo Peña)

Model hierharchy

class ConcreteBase(models.Model):
    ...


class Descendant(ConcreteBase):
    ...

Master / Detail type models (e.g. Order and OrderDetail)

class MasterModel(models.Model):
    ...


class DetailModel(models.Model):
    
    master = models.ForeignKey(MasterModel, ...)
    concrete_base = models.ForeignKey(ConcreteBase, ...)

Form definition

class MasterModelForm(forms.ModelForm):
    ...


class DetailModelForm(forms.ModelForm):
    ...
    # master excluded from fields as will be manually added in view
    ...

Formset definition

DetailModelFormset = inlineformset_factory(MasterModel, DetailModel, form=DetailModelForm)

View definition

from django.views.generic.edit import CreateView #### <---- the error only happens on create view of MasterModel

class MasterModelAdd(CreateView):
    model = MasterModel
    form_class = MasterModelForm
    ...

    def form_valid(self, form):
        master_instance = form.save()
        detail_formset = DetailModelFormset()(self.request.POST)
        detail_instances = detail_formset.save(commit=False) ### <------ this line raises the error
        for detail_instance in detail_instances: ### <----- it never gets here
            detail_instance.master = master_instance
            detail_instance.save()

When calling formset.save() I'm getting an error from django/forms/models.py (line 910) regardless of the value of commit passed.

910:   pk_value = getattr(self.instance, self.fk.remote_field.field_name)
911:   setattr(obj, self.fk.get_attname(), getattr(pk_value, 'pk', pk_value))

The getattr call fails

if I wrap both lines in: if hasattr(self.instance, self.fk.remote_field.field_name):
it works good.

Not sure if the condition is the way to fix the bug or it's just preventing the original cause from happening.

Change History (2)

comment:1 by Tim Graham, 7 years ago

Summary: Formset.save for model with foreign key to concrete base modelFormset.save() crashes for model with foreign key to concrete base model
Type: UncategorizedBug

Could you include more complete details about how to reproduce the issue? My try to reproduce gives save() prohibited to prevent data loss due to unsaved related object 'some_model'. at formset.save().

comment:2 by Lorenzo Peña, 7 years ago

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