Opened 8 years ago

Last modified 4 years ago

#27408 closed New feature

Multiple consecutive `bulk_create`s with FK. — at Initial Version

Reported by: Jarek Glowacki Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords: bulk_create foreign key id
Cc: Triage Stage: Someday/Maybe
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

As of dj110 bulk_create returns pks for the objects it has created. Great! I want more.

Going to hop right into the use case:

class A(models.Model):
    pass


class B(models.Model):
    a = models.ForeignKey(A, on_delete=models.PROTECT)
a = A()
b = B(a=a)  # doesn't set `a_id`, since `a` has no id assigned yet.
A.bulk_create([a])  # sets `a`'s id.
B.bulk_create([b])  # error!

The first bulk_create call sets the id on a, but b.a_id remains None.
When running the second bulk_create, even though b has an a set, it fails to save a onto the b instance, due to a_id being None.

So if you imagine the pregeneration of several related models in a big loop, followed by several consecutive bulk_create calls we run into trouble. It's nicer than having to manually feed in ids during the loop as we needed to in the past, but it still needs some magic.

My current solution is running a little function between each bulk_create call, to fill the foreignkey ids in:

def fill_foreignkey_ids(objects, fields):
    for f in fields:
        for o in objects:
            setattr(o, '%s_id' % f, getattr(o, f).id)

Which makes:

a = A()
b = B(a=a)  # doesn't set `a_id`, since `a` has no id assigned yet.
bulk_a = [a]
bulk_b = [b]
A.bulk_create(bulk_a)  # sets `a`'s id.
fill_foreignkey_ids(bulk_b, ['a'])
B.bulk_create(bulk_b)  # now it works. Lovely.

But this is quite ugly.

This is more of a brainstorm ticket, as I'm not sure how to solve this nicely. Expecting every unsaved model instance to update its foreignkey ids when a bulk_create inserts them sounds seems silly. But maybe we could have the bulk_create method check whether b.a.id is set when b.a_id isn't?

I can submit a PR if this sounds like a reasonable thing to do. It feels a bit magic, but it would greatly improve the usefulness of this new feature.

Change History (0)

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