我有一个可以有一个或多个模型的系统。我已经在数据库中用多对多字段建模了这种关系。下面的代码用于在单个表单中编辑系统及其相关方法。
通过填写表单并按下提交来添加新方法仅在第一次时有效。如果我再做一个小改动并再次提交,我会收到以下消息(由下面的代码生成):
METHODFORMSET.ERRORS: [{}, {'name': [u'Method with this Name already exists.']}]
这是由于 name 字段是唯一的,但它应该已经更新,而不是创建新记录,即使我使用 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
错误,而是首先防止错误发生。我认为实际问题可能与 modelformsets 处理新表单的方式有关。不知何故,它看起来总是试图为最后一个表单集创建一个新实例,无论它是否已经退出。
因此,如果我在添加最后一个表单集后不添加新表单集,则模型表单集将尝试重新创建最后一个表单集(即使它只是在上次提交时创建的)。
最初的情况是我在 methodformset 中有 1 个有效的 Method 实例和 1 个新的未绑定实例。然后我填写表格并点击保存,这将验证两个方法并绑定第二个方法,然后将其保存到表中。到目前为止一切都很好,但是如果我第二次点击保存,就会发生错误。也许这与method-TOTAL_FORMS=2 和method-INITIAL_FORMS=1 的事实有关。难道这会导致modelformset强制在第二种方法上创建?
任何人都可以确认/否认这一点吗?
[在一个周末不看代码后编辑]:
问题是由于我将表单保存在视图中并且在保存之后,我将原始的 methodformset 实例(从保存之前)发送到模板。可以通过在保存后使用查询集而不是 POST 数据重新实例化模型表单集来解决该问题。
因此,防止此类错误的一般规则是在保存后转到不同的页面(完全避免),或者使用上述解决方案。
在我将此作为解决方案发布之前,我需要进行更多测试。