2012-07-27 81 views
1

我有一個可以有一個或多個模型的系統。我已經在數據庫中建立了一個多元關係的關係模型。下面的代碼用於以單一形式編輯系統及其相關方法。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

回答

0

我已經重新實例modelformset

0

您可以在保存表單時驗證每個表單。我創建了一個簡單的例子(類似於你的代碼),它對我來說很好。它創建新的對象,如果沒有這樣的名稱的對象,否則它編輯一個現有的對象。

你需要一個表格編輯您的模型對象:

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

相關問題