2011-11-28 52 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()