#29497 closed Bug (duplicate)

Initializing model instance with an unsaved related object, then saving that related object and then saving the instance doesn't work

Reported by: Robin Ramael Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords: orm, foreign key, bulk_create
Cc: Triage Stage: Unreviewed
Has patch: no 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 (1)

comment:1 Changed 18 months ago by Tim Graham

Resolution: duplicate
Status: newclosed

Duplicate of #29085.

Note: See TracTickets for help on using tickets.
Back to Top