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 来解决。

因此,防止这样的错误的一般规则是在保存之后转到不同的页面(完全避免它)或使用上述解决方案。

在我发布这个解决方案之前,我需要做更多的测试。

+0

OK保存(在这个问题的底部看到编辑)后解决了这个问题,我看到我的答案是不是你的问题。我会审查它。 – sergzach 2012-07-27 10:57:06

+0

原理是相似的,并且需要更复杂的代码,因为我们与模型表单有交易,但与表单无关。 – sergzach 2012-07-27 11:16:21

+0

我改变了我的答案。请查看。 – sergzach 2012-07-27 19:53:03

我已经重新实例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() 

有在你的代码中的一些附加功能。我展示了工作原理。了解解决方案足够了吗?

+0

我不确定我是否理解你的答案。我不认为**方法** .name(而不是system.name)的唯一性是问题,它只是通过在**方法*时生成“此方法名已存在的方法” * formset被验证。真正的问题是,我的代码每次都想创建一个新的Method实例,而不是更新现有的实例。 – 2012-07-27 10:33:57

+0

感谢您使用新的解决方案。如果我理解正确,那么您正在捕获“此名称的方法已存在”错误并为其提供解决方法。我可以将此作为最后的解决方案,但在我看来,代码中存在一个更基本的问题,因为“此名称的方法已存在”错误不应该首先发生。 – 2012-07-28 01:21:03

+0

@JohnPeters我已经改变了我的答案,没有检查'名称'键的解决方案。现在清楚了吗? – sergzach 2012-07-28 07:51:30