Reputation: 2495
I have a model in my app named foo
class foo(models.Model):
a = models.CharField(max_length=500, default=0,null=True)
a_quantity = models.CharField(max_length=500, default=0, null=True)
and I am updating this model from another form like this:
def form_valid (self, form):
product = form.save(commit=False)
product.save()
data = form.cleaned_data
for i in range(1, 9):
foo.objects.update_or_create(a=data["a" + str(i)],
b=data["a_quantity" + str(i)])
But the problem here is that it creates a new entry if a
is same but a_quantity
. I want that when a is repeated its quantity should be summed to the existing quantity in the model.
For eg id my input is this:
bar 10
and the table is like this:
a a_quantity
nar 27
bar 15
lar 10
then when the function is called it should do this:
a a_quantity
nar 27
bar 25
lar 10
Currently it creates a new entry with the same name and different quantity. How can I do this ?
Upvotes: 1
Views: 148
Reputation: 377
I don't understand why you need this:
for i in range(1, 9):
foo.objects.update_or_create(a=data["a" + str(i)],
b=data["a_quantity" + str(i)])
Maybe we could better help you if you show us your forms.py
.
Do not save()
the product if you don't want to save it.
Assuming that bar
value should be 25 instead of 15 as you've shown in the example, you can use get_or_create
instead:
def form_valid (self, form):
data = form.cleaned_data
product, created = foo.objects.get_or_create(
a=data['a'],
defaults={'a_quantity': 0}
)
product.a_quantity += data['a_quantity']
product.save()
First a product is created with quantity as 0 if it does not exist, otherwise it is retrieved. Next, the quantity is updated.
A better option would be to use F expressions here instead. This avoids race conditions and inconsistency when multiple people try to update the same object instance.
from django.db.models import F
def form_valid (self, form):
data = form.cleaned_data
product, created = foo.objects.get_or_create(
a=data['a'],
defaults={'a_quantity': 0}
)
product.a_quantity = F('a_quantity') + data['a_quantity']
product.save()
Upvotes: 0
Reputation: 477608
You set the update value in the defaults=…
parameter of the .update_or_create(..)
method [Django-doc]:
for i in range(1, 9):
foo.objects.update_or_create(
a=data['a' + str(i)],
defaults={'a_quantity': data['a_quantity' + str(i)])}
)
or you can increment the value with the given a_quantity
with:
from django.db.models import F
for i in range(1, 9):
foo.objects.filter(
a=data['a' + str(i)]
).update(
a_quantity=F('a_quantity')+data['a_quantity' + str(i)]
)
I'm however not sure that this is a good idea, since one often aims to make requests idempotent. We can create a record in case no object to update exists:
from django.db.models import F
for i in range(1, 9):
exists = foo.objects.filter(
a=data['a' + str(i)]
).update(
a_quantity=F('a_quantity')+data['a_quantity' + str(i)]
)
if not exists:
foo.objects.create(a=data['a' + str(i)], a_quantity=data['a_quantity' + str(i)])
Some remarks:
a
field as a non-NULLable unique field;PerlCase
, so Foo
, not foo
'a_quantity{}'.format(i)
over constructing strings;range(..)
might not be the best option here, since if there are less than nine updates, it will raise an error, and if there are more, these will not be handled.Upvotes: 2