[Django] #27560: Formset.save for model with foreign key to concrete base model

51 views
Skip to first unread message

Django

unread,
Dec 1, 2016, 1:02:23 PM12/1/16
to django-...@googlegroups.com
#27560: Formset.save for model with foreign key to concrete base model
-------------------------------------+-------------------------------------
Reporter: Lorenzo | Owner: nobody
Peña |
Type: | Status: new
Uncategorized |
Component: Forms | Version: 1.9
Severity: Normal | Keywords: formset
| inline_formset
Triage Stage: | inline_formsetfactory
Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
{{{
class A(models.Model):
pass

class B(A):
pass

class C(models.Model):
some_model = models.ForeignKey(SomeModel)
a_link = models.ForeignKey(A)
}}}

I'm using an inlineformset_factory where the parent model is SomeModel and
the child model is C.
When calling formset.save() I'm getting an error from
django/forms/models.py (line 910)

{{{
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.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 6, 2016, 1:19:07 PM12/6/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------
Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9
Severity: Normal | Resolution:
Keywords: formset | Triage Stage:
inline_formset | Unreviewed
inline_formsetfactory |

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* type: Uncategorized => Bug


Comment:

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()`.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:1>

Django

unread,
Dec 7, 2016, 11:44:23 AM12/7/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9

Severity: Normal | Resolution:
Keywords: formset | Triage Stage:
inline_formset | Unreviewed
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Lorenzo Peña:

Old description:

> {{{
> class A(models.Model):
> pass
>
> class B(A):
> pass
>
> class C(models.Model):
> some_model = models.ForeignKey(SomeModel)
> a_link = models.ForeignKey(A)
> }}}
>
> I'm using an inlineformset_factory where the parent model is SomeModel
> and the child model is C.
> When calling formset.save() I'm getting an error from
> django/forms/models.py (line 910)
>
> {{{
> 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.

New description:

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.

--

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:2>

Django

unread,
Dec 7, 2016, 11:45:00 AM12/7/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9

Severity: Normal | Resolution:
Keywords: formset | Triage Stage:
inline_formset | Unreviewed
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Lorenzo Peña):

Updated ticket to expand context so that bug may be (hopefully)
reproduced.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:3>

Django

unread,
Dec 7, 2016, 12:03:48 PM12/7/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9

Severity: Normal | Resolution:
Keywords: formset | Triage Stage:
inline_formset | Unreviewed
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham):

This report is awfully complicated and without spending more than a few
minutes investigating I can't say whether or not this is a bug in Django
or in your code. One thing to try might be:
`DetailModelFormset(self.request.POST, instance=master_instance)`.

It seems like excluding `master` from `DetailModelForm` may also be
related. (How can you have an inline formset without the field linking the
subforms to the parent?)

It would be nice if you do more to confirm that this is actually a bug,
such as by [wiki:TicketClosingReasons/UseSupportChannels using our support
channels]. Putting together a sample project with a test case that someone
could download to quickly reproduce the issue would also help.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:4>

Django

unread,
Dec 7, 2016, 12:40:51 PM12/7/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9

Severity: Normal | Resolution:
Keywords: formset | Triage Stage:
inline_formset | Unreviewed
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Lorenzo Peña):

I'll have to investigate, but for the record:

1. In this view, I'm creating master and details at the same time, so I
don't have really anything to pass because nothing exists yet.
2. Regarding the fact that I'm omitting the link to master, do you suggest
a hidden field?
3. This exact pattern works in at least one more place in my codebase,
only crashing when the abstract base is involved in the child formset.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:5>

Django

unread,
Dec 14, 2016, 11:18:07 AM12/14/16
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9
Severity: Normal | Resolution:
Keywords: formset | Triage Stage: Accepted
inline_formset |
inline_formsetfactory |

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* stage: Unreviewed => Accepted


Comment:

I haven't investigated any further but tentatively accepting.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:6>

Django

unread,
May 26, 2018, 7:53:08 AM5/26/18
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: new
Component: Forms | Version: 1.9

Severity: Normal | Resolution:
Keywords: formset | Triage Stage: Accepted
inline_formset |
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Bartosz Grabski):

I've tested this and found two issues with your code in `form_valid`:

{{{
...
detail_formset = DetailModelFormset(self.request.POST) <----
there was a bug in your previous code:
DetailModelFormset()(self.request.POST)
if detail_formset.is_valid(): <--- you were missing formset
validation
detail_instances = detail_formset.save(commit=False)
...
}}}

After fixing that, the code works fine.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:7>

Django

unread,
May 26, 2018, 8:03:36 AM5/26/18
to django-...@googlegroups.com
#27560: Formset.save() crashes for model with foreign key to concrete base model
-------------------------------------+-------------------------------------

Reporter: Lorenzo Peña | Owner: nobody
Type: Bug | Status: closed
Component: Forms | Version: 1.9
Severity: Normal | Resolution: invalid

Keywords: formset | Triage Stage: Accepted
inline_formset |
inline_formsetfactory |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Lorenzo Peña):

* status: new => closed
* resolution: => invalid


Comment:

Looks like it was a bug in my code.

--
Ticket URL: <https://code.djangoproject.com/ticket/27560#comment:8>

Reply all
Reply to author
Forward
0 new messages