1

I am just wondering if it's possible to bulk save queries in django.

for example, usually I would have to loop through each object

for obj in queryset:
    if condition:
        obj.field = True
        obj.save()

EDIT:

I know the above case can be handled with the update method. However, the sample above is saving all the fields with the same value. What if there are different conditions?

for obj in queryset:
    if condition:
        obj.field = True
        obj.save()
    else:
        obj.field = False
        obj.save()

The above might not be the best sample I can think of at the moment but something similar I would say.

would there be a faster way to do this?

Thanks in advance for any advices

sytech
  • 29,298
  • 3
  • 45
  • 86
Dora
  • 6,776
  • 14
  • 51
  • 99
  • 1
    Possible duplicate of [How to 'bulk update' with Django?](https://stackoverflow.com/questions/12661253/how-to-bulk-update-with-django) – sytech Jan 17 '18 at 01:11
  • I edited the title, hoping that makes the question being ask more apparent. With the added clarification, provided by the asker, this may not be a duplicate after all. – sytech Jan 17 '18 at 01:45

2 Answers2

3

Querysets have an update method that does precisely this. There are some caveats, however, like model save methods not being called. Keep that in mind if you override and implement your own save methods for your models.

From the django docs:

For example, to turn comments off for all blog entries published in 2010, you could do this:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

So, in other words queryset.update(field='value')

UPDATE: concerning doing this dynamically based on conditionals...

Because update performs at the SQL level (performed by the DB), you would want to work in your condition into your query, which is almost always possible in one way or another. You may do multiple queries to get the effect.

def my_bulk_update():
    MyModel.objects.filter(conditional_field=True).update(field=True)
    MyModel.objects.filter(conditional_field=False).update(field=False)

There are many clever ways you can make queries to accomplish this, (Including annotating, aggregating , expressions and more)... You may be surprised how much logic you can stuff into a query. Be sure to check out the docs on making queries. And of course, you can always write your own SQL to do effectively the same thing, too, if the ORM doesn't quite cut it with generating the query.

If the logic is really complex and can't be done with SQL, you can do roughly as you've already written, but may want to use transactions for performance if you have a large number of records.

sytech
  • 29,298
  • 3
  • 45
  • 86
  • Sorry >.<" I think I forgot another main point of my question. I searched up and saw the `update` But this update will update ALL queryset with same value. What if somehow the value is different for each queryset depending on condition? (let me update my question, sorryz about this) – Dora Jan 17 '18 at 01:14
  • @Dora ah, I think I understand now what you mean. Well, to put shortly, you would probably want to work that `if condition` logic into your query. There are a lot of clever ways you can do this. I'll update my answer in a second, once I do, let me know if there's more clarification you need. – sytech Jan 17 '18 at 01:18
  • @Dora I updated my answer. If you have some specific logic in mind you are curious about how to work some specific basic logic you have in mind into a query, let me know and I'll see if I can accommodate in my answer. If the logic is sufficiently complex, research the docs on making queries or ask another question specifically for that if you can't figure it out. Chances are it can be done with a query. – sytech Jan 17 '18 at 01:30
  • thanks for helping me with the title, I am really bad at giving out titles and seeing your `conditional_field` I do understand more even though still a slight question which is stuck in my mind that I couldn't get it out. Something I ran into but I would give this a correct answer as those two examples are what I have in my head now. Really thanks for the time to explain. – Dora Jan 17 '18 at 01:52
1

If you need to set different values for each record in the database, you can do manual commit.

from django.db import transaction    
...
transaction.set_autocommit(False)
for obj in queryset:
if condition:
    obj.field = random_value
    obj.save()
else:
    obj.field = another_random_value
    obj.save()
transaction.commit()
transaction.set_autocommit(True)
erik
  • 61
  • 5