2011-11-28 146 views
12

保存問題可能類似於this one,但它不是...覆蓋Django上InlineModelAdmin

我有一個模型結構,如:

class Customer(models.Model): 
    .... 

class CustomerCompany(models.Model): 
    customer = models.ForeignKey(Customer) 
    type = models.SmallIntegerField(....) 

我使用InlineModels,並有兩種類型的CustomerCampany.type。所以我定義爲CustomerCompany 2個不同勢在線和OV覆蓋InlineModelAdmin.queryset

class CustomerAdmin(admin.ModelAdmin): 
    inlines=[CustomerCompanyType1Inline, CustomerCompanyType2Inline] 


class CustomerCompanyType1Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType1Inline, self).queryset(request).filter(type=1) 

class CustomerCompanyType2Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2) 

全部是好的,好了這裏,但爲InlineModelAdmin添加新記錄,我仍然需要在AdminForm顯示CustomerCompanytype領域,因爲我不能覆蓋InlineModelAdminsave方法喜歡:

class CustomerCompanyType2Inline(admin.TabularInline): 
    model = CustomerCompany 
    def queryset(self, request): 
     return super(CustomerCompanyType2Inline, self).queryset(request).filter(type=2) 
    #Following override do not work 
    def save_model(self, request, obj, form, change): 
     obj.type=2 
     obj.save() 

使用的信號也沒有因爲我的信號sender將是相同的012中的溶液,這樣我就可以不檢測InlineModelAdmin發送和type必須是什麼?

有什麼辦法可以讓我設定type場之前保存?

回答

23

Alasdair的答案沒有錯,但它有一些可能導致問題的痛處。首先,通過使用form作爲變量名稱循環查看錶單,您實際上覆蓋了傳入方法form的值。這不是什麼大問題,但是既然你可以在沒有從formset提交的情況下進行保存,最好這樣做。其次,所有重要的formset.save_m2m()被排除在答案之外。實際Django docs提出以下建議:

def save_formset(self, request, form, formset, change): 
    instances = formset.save(commit=False) 
    for instance in instances: 
     # Do something with `instance` 
     instance.save() 
    formset.save_m2m() 

你要碰到的問題是,save_formset方法必須在父ModelAdmin而不是內聯,並從那裏,也沒有辦法知道哪些在線實際上正在被利用。如果你有一個帶有兩個「類型」的obj,並且所有字段都是相同的,那麼你應該使用代理模型,並且實際上可以覆蓋每個類型的save方法以自動設置適當的類型。

class CustomerCompanyType1(CustomerCompany): 
    class Meta: 
     proxy = True 

    def save(self, *args, **kwargs): 
     self.type = 1 
     super(CustomerCompanyType1, self).save(*args, **kwargs) 

class CustomerCompanyType2(CustomerCompany): 
    class Meta: 
     proxy = True 

    def save(self, *args, **kwargs): 
     self.type = 2 
     super(CustomerCompanyType2, self).save(*args, **kwargs) 

然後,你不需要做任何特別的事情與你的內聯。只需更改現有的內聯管理員類以使用其適當的代理模型,並且所有內容都將自行排除。

+0

+1好方法使用代理模型。我更新了我的答案,以解決您提到的最明顯的錯誤。這仍然留下了解決formset所代表的問題。 – Alasdair

+0

實際上,代理模型方法消除了覆蓋'save_formset'的需要。代理本身已經重寫了'save'方法,知道如何將其保存爲正確的類型。所以,你只需使用內聯而不用擔心它。 –

+0

我的評論是不明確的 - 我同意,即使是在'save_formset'('save_m2m'等)固定問題後,仍然有其內嵌的你保存的問題。我理解的是,代理模型方法避免了:) – Alasdair

5

有一個save_formset方法,你可以覆蓋。你必須弄清楚內聯代表formset

def save_formset(self, request, form, formset, change): 
    instances = formset.save(commit=False) 
    for instance in instances: 
     # Do something with `instance` 
     instance.save() 
    formset.save_m2m() 
0

其他答案是正確的,當涉及到使用save_formset。他們缺少一種方法來檢查當前保存的模型。要做到這一點,你可以:

if formset.model == CustomerCompany: 
    # actions for specific model 

這將使外觀save_formset功能,如:(假設你只是想覆蓋保存的具體型號(S))

def save_formset(self, request, form, formset, change): 

    # if it's not the model we want to change 
    # just call the default function 
    if formset.model != CustomerCompany: 
     return super(CustomerAdmin, self).save_formset(request, form, formset, change) 

    # if it is, do our custom stuff 
    instances = formset.save(commit=False) 
    for instance in instances: 
     instance.type = 2 
     instance.save() 
    formset.save_m2m()