Django modelformset创建新记录而不是更新现有的记录
我有一个可以有一个或多个模型的系统。我已经在数据库中建立了一个多元关系的关系模型。下面的代码用于以单一形式编辑系统及其相关方法。Django modelformset创建新记录而不是更新现有的记录
填写其形式和紧迫只提交第一次作品添加新方法。如果我那么做一个小的变化,然后再次提交,我得到以下信息(由下面的代码生成):
METHODFORMSET.ERRORS: [{}, {'name': [u'Method with this Name already exists.']}]
这是一个事实,即名称字段是唯一引起的,但它应该有更新,不创建一个新的纪录,即使我使用POST数据生成methodformset实例...
请注意这种行为只适用于最后一个附加方法的实例,而不是那些已经存在在桌子里。
这里是相关的代码,任何人都可以让我知道我在做什么错了吗?
def sysedit(request, sys_id):
system = System.objects.get(id=sys_id)
MethodFormSet = modelformset_factory(Method, form=MethodForm)
post = None
if request.POST:
post = request.POST.copy()
if 'add_method' in request.POST:
post['method-TOTAL_FORMS'] = repr(int(
post['method-TOTAL_FORMS'])+ 1)
systemform = SystemForm(data=post, instance=system)
methodformset = MethodFormSet(data=post, prefix='method',
queryset=Method.objects.filter(id__in=system.method.all()))
if methodformset.is_valid():
mfs = methodformset.save()
print 'SAVED-method', mfs
for mf in mfs:
if systemform.is_valid():
sp = systemform.save(mf)
print 'SYSTEM', sp
else:
print 'SYSFORMSET.ERRORS:', systemform.errors
else:
print 'METHODFORMSET.ERRORS:', methodformset.errors
return render_to_response('sysedit.html',
{'systemform': systemform,
'methodformset': methodformset,
'system': system},
context_instance=RequestContext(request))
class System(models.Model):
method = models.ManyToManyField(Method)
...
class Method(models.Model):
name = models.CharField(unique=True)
...
class MethodForm(ModelForm):
class Meta:
model = Method
class SystemForm(ModelForm):
def save(self, new_method=None, commit=True, *args, **kwargs):
m = super(SystemForm, self).save(commit=False, *args, **kwargs)
if new_method:
m.method.add(new_method)
if commit:
m.save()
return m
class Meta:
model = System
exclude = ('method')
[后Sergzach的回答编辑]:
的问题不在于如何应对Method with this name already exists
错误,但要防止来自于未然。我认为实际问题可能与模型表单处理新表单的方式有关。不管怎样,它看起来总是试图为最后一个formset创建一个新实例,而不管它是否已经退出。
所以如果我在最后一个被追加后没有添加新的表单集,那么modelformset会尝试重新创建最后一个表单(尽管它刚刚在前一个提交中创建)。
最初的情况是,我在methodformset中有1个有效的Method实例和1个新的未绑定实例。然后我填写表单并点击保存,这将验证两个方法并绑定第二个,然后将其保存到表中。 到目前为止一切都很顺利,但如果我再次点击保存第二次错误发生。也许这与方法-TOTAL_FORMS = 2和method-INITIAL_FORMS = 1这一事实有关。这是否会导致modelformset在第二个方法上强制创建?
任何人都可以确认/否认这一点?
[不看代码一个周末后编辑]:
的问题是由我保存在视图中,并保存后的形式造成的事实,我送原methodformset实例(从前保存)到模板。该问题可以通过使用queryset而不是POST数据在保存之后重新实例化modelformset 来解决。
因此,防止这样的错误的一般规则是在保存之后转到不同的页面(完全避免它)或使用上述解决方案。
在我发布这个解决方案之前,我需要做更多的测试。
我已经重新实例modelformset
您可以在保存表单时验证每个表单。我创建了一个简单的例子(类似于你的代码),它对我来说很好。它创建新的对象,如果没有这样的名称的对象,否则它编辑一个现有的对象。
你需要一个表格编辑您的模型对象:
class EditMethodForm(forms.ModelForm):
class Meta:
model = Method
exclude = ('name',)
然后代替methodformset.is_valid()你做下:
for methodform in methodformset:
try:
instance = Method.objects.get(name = request.POST[ 'name' ])
except Method.DoesNotExist:
methodform.save()
else:
editmethodform = EditMethodForm(request.POST, instance = instance)
if editmethodform.is_valid():
editmethodform.save()
有在你的代码中的一些附加功能。我展示了工作原理。了解解决方案足够了吗?
我不确定我是否理解你的答案。我不认为**方法** .name(而不是system.name)的唯一性是问题,它只是通过在**方法*时生成“此方法名已存在的方法” * formset被验证。真正的问题是,我的代码每次都想创建一个新的Method实例,而不是更新现有的实例。 – 2012-07-27 10:33:57
感谢您使用新的解决方案。如果我理解正确,那么您正在捕获“此名称的方法已存在”错误并为其提供解决方法。我可以将此作为最后的解决方案,但在我看来,代码中存在一个更基本的问题,因为“此名称的方法已存在”错误不应该首先发生。 – 2012-07-28 01:21:03
@JohnPeters我已经改变了我的答案,没有检查'名称'键的解决方案。现在清楚了吗? – sergzach 2012-07-28 07:51:30
OK保存(在这个问题的底部看到编辑)后解决了这个问题,我看到我的答案是不是你的问题。我会审查它。 – sergzach 2012-07-27 10:57:06
原理是相似的,并且需要更复杂的代码,因为我们与模型表单有交易,但与表单无关。 – sergzach 2012-07-27 11:16:21
我改变了我的答案。请查看。 – sergzach 2012-07-27 19:53:03