Opened 6 years ago
Closed 4 years ago
#29497 closed Bug (fixed)
Saving parent object after setting on child leads to unexpected data loss in bulk_create().
Reported by: | Robin Ramael | Owned by: | Hannes Ljungberg |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | orm, foreign key, bulk_create |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Example:
class Country(models.Model): name = models.CharField(max_length=255) iso_two_letter = models.CharField(max_length=2) description = models.TextField() class City(models.Model): name = models.CharField(max_length=255) country = models.ForeignKey(Country, on_delete=models.CASCADE) class BulkCreateTests(TestCase): def test_fk_bug(self): country_nl = Country(name='Netherlands', iso_two_letter='NL') country_be = Country(name='Belgium', iso_two_letter='BE') city = City(country=country_be, name='Brussels') # (1) country_be.save() # (2) city.save()
This results in an integrity error:
====================================================================== ERROR: test_fk_bug (bulk_create.tests.BulkCreateTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/robin/src/django/django/db/backends/utils.py", line 85, in _execute return self.cursor.execute(sql, params) psycopg2.IntegrityError: null value in column "country_id" violates not-null constraint DETAIL: Failing row contains (1, Brussels, null). The above exception was the direct cause of the following exception: ... ----------------------------------------------------------------------
I wonder wether there's a reason that this doesn't work. If setting a related object on a model instance automatically sets instance.related_object_id, you'd expect this behavior to continue working if the related object receives its primary key after the referencing instance was initialized.
Of course, switching lines (1) and (2) makes it all work, but this behavior means that bulk creating with related objects (with postgres returning the primary keys, bless it's heart) becomes more complex than it should be, forcing the user to use mappings or even set the foreign keys themselves:
for country_data, city_data in data: country = Country(**country_data) countries.append(country) city = City(country=country, **city_data) cities.append(city) Country.objects.bulk_create(countries) # needs this for the bulk create to not give an integrity error: for city in cities: city.country_id = city.country.id City.objects.bulk_create(cities)
Ideally, the main instance would, when saved, 'reach into' its related objects and set the foreign key field like the loop does. Is there a reason this can't work?
Change History (4)
comment:1 by , 6 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
comment:2 by , 4 years ago
Resolution: | duplicate |
---|---|
Status: | closed → new |
Summary: | Initializing model instance with an unsaved related object, then saving that related object and then saving the instance doesn't work → Saving parent object after setting on child leads to unexpected data loss in bulk_create(). |
Triage Stage: | Unreviewed → Accepted |
Duplicate of #29085.