2012-04-27 28 views
7

非常基本的使用場景在這裏允許save_formset的進一步壓倒一切的。我想保存創建對象的用戶和上次修改對象的用戶。然而,這是一個內聯的模型,所以我當然需要使用save_formset。 Django文檔具有下面的示例代碼:上的ModelAdmin

class ArticleAdmin(admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for instance in instances: 
      instance.user = request.user 
      instance.save() 
     formset.save_m2m() 

的事情是,如果你注意到,由於super不會被調用,這是一條死衚衕。如果ModelAdmin的子類,而該方法以同樣的方式覆蓋,你失去父固有的功能。這一點很重要,因爲這是這樣的,我想分解出功能的常見的使用場景,所以我創建了以下內容:

class TrackableInlineAdminMixin(admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for instance in instances: 
      if hasattr(instance, 'created_by') and hasattr(instance, 'modified_by'): 
       if not instance.pk: 
        instance.created_by = request.user 
       instance.modified_by = request.user 
      instance.save() 
     formset.save_m2m() 
     super(TrackableInlineAdminMixin, self).save_formset(request, form, formset, change) 

我上漲了調用super出於習慣比什麼都重要,不要以爲它實際上會導致formset保存兩次。儘管如此,除了一種情況外,它仍然適用於每種情況:刪除只要您嘗試在管理員中刪除內聯,就會收到錯誤消息。錯誤的很模糊,並沒有真正relavent在這裏我的問題,但我相信它涉及到試圖挽救後再次你只是刪除了它的一個實例的表單集。當super的呼叫被移除時,代碼工作得很好。

長和短,有沒有什麼辦法可以讓我缺少定製保存行爲允許子類自己重寫?

+2

剛剛發現[一個未解票(https://code.djangoproject.com/門票/ 17988) – okm 2012-04-30 10:50:58

回答

5

這是一個doozie。

我有一些有趣的閒逛,看來所有的行動發生在這裏django.forms.models.BaseModelFormSet

的問題是不管ModelFormSet.save()刪除的commit標誌的情況下,沒有修改的形式來反映被刪除的狀態。

如果您再次調用save(),它會遍歷表單,並在ModelChoiceField清理嘗試拉起引用的ID並引發無效的選擇錯誤。

​​

我能解決這個問題的唯一方法是修補BaseModelFormset.save_existing_objects如果一個對象被刪除從self.forms刪除形式。

做了一些測試,並沒有出現任何不良影響。

+0

感謝您的詳細分析。我只是想要一個完整的檢查來確保我不是完全錯過了一些東西,但是如果Django源需要補丁,那麼這看起來像是一個錯誤報告的主要候選者。 – 2012-04-30 16:46:24

0

@克里斯普拉特幫助:

我上漲了調用超出於習慣比什麼都重要的, 不認爲它實際上將導致表單集保存兩次。

我試圖進一步覆蓋save_formset爲了發送後保存信號。我只是不明白,調用super()只是第二次保存formset。

爲了應對super()問題,我創建了一個save_formset_now方法與我的自定義代碼,我打電話的時候我通過admin.ModelAdmin孩子覆蓋save_formset

這是代碼,這似乎也照顧刪除問題,使用Django 1.10在2016年

class BaseMixinAdmin(object): 
    def save_formset_now(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for obj in formset.deleted_objects: 
      obj.delete() 
     for instance in instances: 
      # *** Start Coding for Custom Needs *** 
       .... 
      # *** End Coding for Custom Needs *** 
      instance.save() 
     formset.save_m2m() 

class BaseAdmin(BaseMixinAdmin, admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     self.save_formset_now(request, form, formset, change) 


class ChildAdmin(BaseAdmin): 
    def save_formset(self, request, form, formset, change): 
     self.save_formset_now(request, form, formset, change) 
     my_signal.send(...)