This raises no errors, and saves book with a null author, because the author's PK field was still None at the time it was assigned.

Ideally, this would store the author, pull out the PK at save time rather than assignment time, and raise an error if the author still isn't saved when book.save() is called (and even more ideally, book would hook the author's save and set self.author_id as soon as the author is saved). Minimally, though, it should raise an error at assignment time to avoid the silent, confusing failure.

(Of course, using create() instead of the object constructor avoids this by saving immediately, but that's not always what's wanted.)

During the validation phase, in BaseModelForm._post_clean, the model formset attemps to build an in memory representation of the object created by the inline and to attach the parent. This fails as soon as you can't attach unsaved objects to foreign keys.

Russell helped me track this down inside InlineModelAdmin, but I couldn't find a fix. Here's what we understood.

1) To create the formset for the admin inline, Django calls InlineModelAdmin.get_formset without a fields keyword argument.

2) get_formset build the list of fields for the form based on the fieldsets defined for the InlineModelAdmin: fields = flatten_fieldsets(self.get_fieldsets(request, obj))

4) InlineModelAdmin.get_fields attempts to obtain the list of fields from its formset's form, which it obtains with form = self.get_formset(request, obj, fields=None).form.

5) At this point we're extremely close to an infinite recursion, but passing the fields keyword argument avoids it. This looks very fragile and I wouldn't be surprised if there was a design error in this area. Since fields is explicitly set to None, the inner get_formset uses forms.ALL_FIELDS instead.

6) InlineModelAdmin.get_fields returns form.base_fields which contains all fields if the InlineModelAdmin.form wasn't set to a particular form class.

6) We're back in the outer InlineModelAdmin.get_formset where this list of fields gets passed explicitly to inlineformset_factory.

Thus, the field representing the foreign key to the parent ends up being explicitly included in the formset's form, which is the root cause of these test failures.

Jacob thinks that wontfixing on the basis that a) the problem is complicated b) the current behavior might be useful isn't the answer, because it's still a bug that can result in data loss, no matter how much we document it.

Given that the problem still existed 4 months ago, that I failed to fix it after a non-negligible amount of effort (meaning it isn't trivial), and that I'm not aware of any changes in this area since then (and I would probably have noticed), I tend to think it isn't fixed.

It looks like you got to roughly the same place as Aymeric did in his attempt to solve this (running into problems with InlineModelAdmin). I'm not really inclined to look into it myself since Aymeric already tried and it's not clear fixing this ticket will yield much benefit -- from an earlier comment: "Jacob thinks that wontfixing on the basis that a) the problem is complicated b) the current behavior might be useful isn't the answer, because it's still a bug that can result in data loss, no matter how much we document it."

The problem is that when in the inline test(which causes errors), we are trying to create an object on the fly and then since it has no id so it cannot be used. Following Aymeric's comments above line by line its true that form gets fields: ['et', 'place'] out of which et which is FK creates problem in form validation step in _post_clean when construct_instance is called.
We need a saved object of ExtraTerrestrial class for its id to be saved in Sighting.

As far as I think, there are other tests in same test file with models using the FK, why not try to implement the error causing test case in a similar way/ or create an object before and send it(dunno if the second part is possible)
Or
Is it possible to write a check in _post_clean and prevent calling of construct_instance?

Need some guidance here.

A similarity between failing tests: Both are dealing with inherited models. Although I don't think that might be a problem here but still I thought it better to post.

In database instead of id in ExtraTerrestrial there is a field lifeform_ptr_id, which never gets a value. I have tried out printing out id of the ET object before and after save is called but it comes out None. So the problem lies there.

Even before the fix for this bug was written, I don't know how the tests passes because the id has always been None, so I do not understand how were the tests passing.
Are ids pulled out again at a later point??