Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Django bulk_create objects in foreign keys?

I was reading up on Django bulk_create and a few of its "flaws":

"
This has a number of caveats though:

1. The model's save() method will not be called, and the pre_save and post_save signals will not be sent.
2. It does not work with child models in a multi-table inheritance scenario.
3. If the model's primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does.
"

I didn't fully understand it. So if I have a list of objects, pass it into bulk_create:

objList = [a, b, c,] #none are saved
model.objects.bulk_create(objList)

Could I still use these objects in foreign keys fine?

for obj in objList:
    o = otherModel(something='asdfasdf', fkey=obj)
    o.save() # will this be fine given the caveats stated above?

So will the foreignKey relation be okay? Also when it says 2. It does not work with child models in a multi-table inheritance scenario, it means that any model that inherits from another model(abstract or not) cannot use bulk_create?

like image 525
Derek Avatar asked May 29 '12 12:05

Derek


People also ask

Does Django automatically index foreign keys?

Django automatically creates an index for all models. ForeignKey columns. From Django documentation: A database index is automatically created on the ForeignKey .

How do foreign keys work in Django?

Introduction to Django Foreign Key. A foreign key is a process through which the fields of one table can be used in another table flexibly. So, two different tables can be easily linked by means of the foreign key. This linking of the two tables can be easily achieved by means of foreign key processes.

How do I add a ForeignKey to a Django model?

Create a (default) object of the foreign model. It will automatically have id=1 (if no object existed yet). Change your foreignkey field by replacing null=True, blank=True by default=1 to associate that new object you created to all existing rows.


2 Answers

Try setting the ids manually. To prevent race conditions, make sure to wrap the function as a single transaction.

from django.db import transaction, models

@transaction.commit_on_success
def bulk_create_with_manual_ids(foo_list):
    id_start = (Foo.objects.all().aggregate(models.Max('id'))['id__max'] or 0) + 1
    for i,foo in enumerate(foo_list): foo.id = id_start + i
    return Foo.objects.bulk_create(foo_list)

objList = [Foo(),Foo(),Foo()]
foo_objects = bulk_create_with_manual_ids(objList)
Bar(foo=foo_objects[0]).save()

Note that this approach is unsuitable for any table that has a serial field or other auto-incrementing in-database generated key. The key will not be incremented by the bulk create since IDs are being generated on the Django side.

like image 122
egafni Avatar answered Sep 22 '22 12:09

egafni


For the first question, no you won't be able to do that, because obj won't have its primary key set so couldn't be used as a foreign key.

The second question, no that's not what it says at all. It specifically mentions "multi-table inheritance": inheriting from an abstract model is not multi-table inheritance.

like image 27
Daniel Roseman Avatar answered Sep 26 '22 12:09

Daniel Roseman