1

i'm trying to overwrite save method in my forms.py ,i have to prevent from creating duplicated objects , and if the object exists only update some fields

class Item(models.Model): item = models.ForeignKey(Product,on_delete=models.CASCADE) quantity = models.IntegerField() 

for example if i entered this data before : item = XYZ , quantity = 100 i want to prevent from creating another XYZ item , i want to just update the quantity , for example i'll enter this data item = XYZ , quantity = 200 i try to prevent from creating this duplicate data , i just try to update the quantity previous quantity + new quantity 100 + 200 = 300 i must update the quantity to 300 for that purpose i overwrite save() in my forms.py

class ItemForm(forms.ModelForm): class Meta: model = Item fields = ['item','quantity'] def save(self,*args,**kwargs): if self.instance.item is None: #i also tried this if not self.instance.item return super().save(*args,**kwargs) else: Item.objects.filter(item__name=self.instance.item).update( quantity=F('quantity') + self.instance.quantity) 

my views.py

def createNewProduct(request): form = ItemForm() if request.method == 'POST': form = ItemForm(request.POST) if form.is_valid(): form.save() return render(request,'temp/add_item.html',{'form':form}) 

but it only update if it exists if not exists it doesn't create any new object , iexpect to create new object if it didn't exists , isn't there any way to achieve it please ? or i didn't something wrong ?

2 Answers 2

2

This is How I usually overwrite save method in model form:

def save(self, commit=True): # your logic or Save your object for example: obj = Model.objects.create(...) return obj 

Or you can also do this:

def save(self, commit=True): obj = super().save(commit=False) # do you logic here for example: obj.field = something if commit: # Saving your obj obj.save() return obj 
Sign up to request clarification or add additional context in comments.

2 Comments

it doesnt work , i tried several times but not work
what do you mean by it doesn't work. I have done it several times... you mean it doesn't save your obj ?
1

According to the documentation for ModelForm.save():

A subclass of ModelForm can accept an existing model instance as the keyword argument instance; if this is supplied, save() will update that instance. If it’s not supplied, save() will create a new instance of the specified model.

This means that in your createNewProduct view, when handling POST requests, you need to check whether an Item already exists in the database and if so pass it to the Form constructor for editing, otherwise instantiate the ModelForm as per usual to create a new Item. So actually there's no need to override the ModelForm's save method

Since you want to add the old and new quantities instead of overwriting them you need to take care of that before the form is saved. This should typically happen in the form's clean method.

The resulting ItemForm and createNewProduct view would then look like this:


class ItemForm(forms.ModelForm): class Meta: model = Item fields = ['item','quantity'] def clean(self): cleaned_data = super().clean() # if this Item already exists if self.instance: # add the old quantity to the new quantity cleaned_data['quantity'] += self.instance.quantity return cleaned_data def createNewProduct(request): if request.method == 'POST': try: dbItem = Item.objects.get(item=request.POST['item']) except Item.DoesNotExist: # get form for new Item form = ItemForm(request.POST) else: # get form for existing Item form = ItemForm(request.POST,instance=dbItem) finally: if form.is_valid(): form.save() return redirect('success') # redirect on success return redirect('failure') #redirect on failure else: form = ItemForm() return render(request,'temp/add_item.html',{'form':form}) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.