How to update multiple model objects at a time with bulk_update?

Viewed 3193

Here from the frontend user gives the input values like this ['1','2', '3']. I want to update the multiple objects at time with bulk_update and I tried like this but this is giving me this error.

ValueError: All bulk_update() objects must have a primary key set.

With this similar way I created objects with bulk_create method which worked fine but with bulk_update it is not workin.

Here I want to update multiple model objects with different values at a time ?

class PVariant(models.Model):
    name = models.CharField(max_length=255)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    ....

#views

quantity = request.POST.getlist('quantity')
#['1','2','3']
names = request.POST.getlist('names')
fields = ['name', 'price', 'quantity'..]
params = zip(names, quantity, weight,..)
variants = [PVariant(name=param[0],sku=param[1], quantity=param[2], weight=param[3],
                                       product=product) for param in params]
PVariant.objects.bulk_update(variants, fields)
          

EDIT: From the client side I am getting this types of data in the view.

['name1', 'name2'] names
['12', '1213.0'] field1
['12.0', '12.0']  field2
['1244', '1244']  field3
['11', '11']   field4
['12.0', '12.0'] field5
2 Answers

Solution

This can be achieved in two queries regardless of number of variants that need to be updated.

You just need to index your data properly on client side so that you can determine which updates to apply to which field server-side.

pvs = PVariant.objects.filter(id__in=pvs_indexed_by_id.keys())

for pv in pvs:
    data = pvs_indexed_by_id[pv.id]
    
    pv.name = data[“name”]
    ...

PVariant.objects.bulk_update(pvs, [“name”, ...])

If you are unable to modify the data shape client side simply clean up the data prior to the code above:

fields = (“name”, “field1”, ...)

data = {}

for i, field enumerate(request.POST):
    data[fields[i]] = field[i]

All PVariant objects should be saved first (call save method) before update. Something like:

variants = []
for param in params:
   inst = PVariant(display_name=param[0],sku=param[1], quantity=param[2], weight=param[3], product=product)
   inst.save()
   variants.append(inst)
Related