Opened 6 years ago

Last modified 6 years ago

#29367 closed Bug

bulk_create with manual primary_key don't update instances state — at Initial Version

Reported by: Oscar Esgalha Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords: bulk_create, primary_key
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given a model with manually defined primary keys:

class State(models.Model):
    two_letter_code = models.CharField(max_length=2, primary_key=True)

Performing a bulk_create with model instances will not correctly update their state.
Looping through the instances and calling save() individually will result in instances with different state from instances persisted with bulk_create:

state_ca = State(two_letter_code='CA')
State.objects.bulk_create([state_ca])
state_ca._state.adding  # => True
state_ca._state.db  # => None

state_ny = State(two_letter_code='NY')
state_ny.save()
state_ny._state.adding  # => False
state_ny._state.db  # => 'default'

One implication of this behavior is that the instances saved with bulk_create can't be used to build relationships with model instances loaded with other Queryset API methods.

Here is a demonstration:

class Group(models.Model):
    ext_id = models.CharField(primary_key=True, max_length=32)


class Analist(models.Model):
    ext_id = models.CharField(primary_key=True, max_length=32)
    groups = models.ManyToManyField(Group)


group_aaa = Group.objects.get(ext_id='AAA')

analist_eee = Analist(ext_id='EEE')
Analist.objects.bulk_create([analist_eee])

analist_eee.groups.set([group_aaa])  # ValueError: Cannot add "<Group: AAA>": instance is on database "None", value is on database "default"

It fails when the ._state.db is compared.

A current workaround option is to manually set the ._state.db after the bulk_create:

 analist_eee = Analist(ext_id='EEE')
Analist.objects.bulk_create([analist_eee])
analist_eee._state.db = 'default'

analist_eee.groups.set([group_aaa]) # And now it works

Change History (0)

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