如何以 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 quantity
100 + 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 模型中的保存方法覆盖为使用 celery 异步的最佳实践