Opened 6 years ago

Last modified 6 years ago

#29367 closed Bug

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

Reported by: Oscar Esgalha Owned by: Oscar Esgalha
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 (last modified by Oscar Esgalha)

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 Analyst(models.Model):
    ext_id = models.CharField(primary_key=True, max_length=32)
    groups = models.ManyToManyField(Group)


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

analyst_eee = Analyst(ext_id='EEE')
Analyst.objects.bulk_create([analyst_eee])

analyst_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:

 analyst_eee = Analyst(ext_id='EEE')
Analyst.objects.bulk_create([analyst_eee])
analyst_eee._state.db = 'default'

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

Change History (3)

comment:1 by Oscar Esgalha, 6 years ago

Owner: changed from nobody to Oscar Esgalha
Status: newassigned

comment:2 by Oscar Esgalha, 6 years ago

comment:3 by Oscar Esgalha, 6 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top