Aggregating save()s in Django? Aggregating save()s in Django? django django

Aggregating save()s in Django?


EDITED: commit_on_success is deprecated and was removed in Django 1.8. Use transaction.atomic instead. See Fraser Harris's answer.

Actually this is easier to do then you think. You can use transactions in Django. These batch database operations (specifically save, insert and delete) into one operation. I've found the easiest one to use is commit_on_success. Essentially you wrap your database save operations into a function and then use the commit_on_success decorator.

from django.db.transaction import commit_on_success@commit_on_successdef lot_of_saves(queryset):    for item in queryset:        modify_item(item)        item.save()

This will have a huge speed increase. You'll also get the benefit of having roll-backs if any of the items fail. If you have millions of save operations then you may have to commit them in blocks using the commit_manually and transaction.commit() but I've rarely needed that.

Hope that helps,

Will


New as of Django 1.6 is atomic, a simple API to control DB transactions. Copied verbatim from the docs:

atomic is usable both as a decorator:

from django.db import transaction@transaction.atomicdef viewfunc(request):    # This code executes inside a transaction.    do_stuff()

and as a context manager:

from django.db import transactiondef viewfunc(request):    # This code executes in autocommit mode (Django's default).    do_stuff()    with transaction.atomic():        # This code executes inside a transaction.        do_more_stuff()

Legacy django.db.transaction functions autocommit(), commit_on_success(), and commit_manually() have been deprecated and will be remove in Django 1.8.


I think this is the method you are looking for: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create

Code copied from the docs:

Entry.objects.bulk_create([    Entry(headline='This is a test'),    Entry(headline='This is only a test'),])

Which in practice, would look like:

my_entries = list()for i in range(100):    my_entries.append(Entry(headline='Headline #'+str(i))Entry.objects.bulk_create(my_entries)

According to the docs, this executes a single query, regardless of the size of the list (maximum 999 items on SQLite3), which can't be said for the atomic decorator.

There is an important distinction to make. It sounds like, from the OP's question, that he is attempted to bulk create rather than bulk save. The atomic decorator is the fastest solution for saving, but not for creating.