How to bulk update Django model values ?

Hi, so i know how to do single value update, and thats what i was trying in the below code

I want to update my links as they are messed up so this is what i did.

from testing.models import retailer

prods = retailer.objects.filter(shop = "Adidas", category = "Slippers")

links = []

serial = []

for all in prods:
  links.append(f'https://adidas.com{all.links.replace("https://adidas.com","")}')
  serial.append(all.id)


for serial,links in zip(serial,links):
  retialer.objects.filter(id=serial).update(links=links)

but i get an error in the end, int object is not iterable

Please Help, Thanks

Which line is throwing the error?

(Note: There’s an easier way to do this, but let’s handle this first.)

@ KenWhitesell
I’d bet money on the id since it says int and the id is not only an int, but in the loop.

@ firaki12345
I know this doesn’t solve the issue you’re having with your current methodology, but I’d just use SQL and do it on the DB end. I’d just write some updates. But maybe you don’t have access to you DB backend?

But I’d just do something like update prods set links = ‘blahblah’ where links = ‘blahblah’ if you’re trying to update everything that matches that where anyway.

I’d cover that bet, with odds.

I’ve got a suspicion I know what it likely is, but the complete traceback wasn’t provided and I’ve got the feeling that this is a “retype” of the code used and not a copy/paste. (Notice the misspelling of “retialer” on the last line.)

So rather than make guesses, I’ll wait for the OP to post the traceback.

hi sorry for the confusion. i finally figured it out thanks to another thread.

for item in prods:
    link = f'https://...'
    item.links = link
    item.save()

hi sorry for the confusion. i finally figured it out thanks to another thread.

for item in prods:
    link = f'https://...'
    item.links = link
    item.save()

works very well

It works - but you’re executing separate queries for each item.

The update function on a queryset performs the updates on all members of the queryset, not just one at a time.

So, assuming that you’re trying to strip the first 18 characters from the links field of the retailer class, your entire block of code can be replaced by:

Retailer.objects.filter(
    shop='Adidas', 
    category='Slippers', 
    links__startswith='https://adidas.com'
).update(links=Substr(F('links'), 19))

It will be a benefit to you to start thinking of querysets as sets upon which operations can be performed - where those operations are performed on every member of the set without needing to explicitly iterate over those elements of that set.

Similarly, if for some reason you needed to iterate over those elements, it’s a lot better to do something like:

prods = retailer.objects.filter(shop = "Adidas", category = "Slippers")

for prod in prods:
    prod.links = 'new link'
    prod.save()

No need for you to manage indexes and explicit references.

(The first version above is still far superior to this, this would be useful if what you needed to do couldn’t be done in the context of an update function.)

Side note:

This is not correct in that you’re reassigning the values of serial and links to the elements of serial and links. You need to use different variables for the lists than for the elements you’re referring to in the list.

When you need to do something like this, the more appropriate pattern would be closer to:

links = []
serials = []

for serial, link in zip(serials, links):
    ...

(Note the change in variable names.)

1 Like