如何以 django 模型形式覆盖保存方法

Posted

技术标签:

【中文标题】如何以 django 模型形式覆盖保存方法【英文标题】:how to overwrite save method in django model form 【发布时间】:2021-08-11 22:52:40 【问题描述】:

我正在尝试覆盖我的 forms.py 中的保存方法,我必须防止创建重复的对象,如果对象存在只更新一些字段

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

例如,如果我之前输入了此数据:item = XYZ , quantity = 100 我想阻止创建另一个 XYZ 项目,我只想更新数量,例如我将输入此数据item = XYZ , quantity = 200 我试图阻止创建这个重复的数据,我只是尝试更新数量previous quantity + new quantity100 + 200 = 300我必须更新quantity to 300为此我覆盖save()在我的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)            

我的意见.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)

但它只在它存在时更新,如果不存在它不会创建任何新对象,如果它不存在,我希望创建新对象,请问有没有办法实现它?还是我没有错?

【问题讨论】:

【参考方案1】:

这就是我通常以模型形式覆盖保存方法的方式:

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

或者你也可以这样做:

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

【讨论】:

不行,试了好几次都不行 你的意思是它不起作用。我已经做了好几次了......你的意思是它不保存你的 obj ?【参考方案2】:

根据documentation for ModelForm.save():

ModelForm 的子类可以接受现有模型实例作为 关键字参数实例;如果提供,save() 将更新 那个例子。如果未提供, save() 将创建一个新实例 指定型号的。

这意味着在你的 createNewProduct 视图中,当处理 POST 请求时,你需要检查一个 Item 是否已经存在于数据库中,如果存在则将它传递给 Form 构造函数进行编辑,否则实例化ModelForm 像往常一样创建一个新项目。所以其实不需要重写ModelForm的save方法

由于您想添加新旧数量而不是覆盖它们,因此您需要在保存表单之前处理好这一点。这通常应该发生在表单的 clean 方法中。

生成的 ItemForm 和 createNewProduct 视图将如下所示:


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)  

【讨论】:

以上是关于如何以 django 模型形式覆盖保存方法的主要内容,如果未能解决你的问题,请参考以下文章

使用覆盖保存为抽象模型扩展 Django ModelForm

Django覆盖保存

Django - 覆盖模型保存()

将 Django 模型中的保存方法覆盖为使用 celery 异步的最佳实践

django views.py 中的保存方法在模型中覆盖后不起作用,py

Django 信号与覆盖保存方法