覆盖Django InlineModelAdmin上的保存

Fal*_*gel 15 django django-modeladmin

这个问题可能类似于这一个,但它不是...

我有一个模型结构,如:

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

class CustomerCompany(models.Model):
    customer = models.ForeignKey(Customer)
    type = models.SmallIntegerField(....)
Run Code Online (Sandbox Code Playgroud)

我正在使用InlineModels,有两种类型CustomerCampany.type.所以我为CustomerCompany和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)
Run Code Online (Sandbox Code Playgroud)

所有这些都是好的,好了这里,但是对于添加新记录InlineModelAdmin,我仍然需要显示设备type的领域CustomerCompanyAdminForm,因为我不能覆盖save的方法InlineModelAdmin ,如:

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()
Run Code Online (Sandbox Code Playgroud)

使用信号也不是一个解决方案,因为我的信号sender是相同的Model,所以我无法检测哪个InlineModelAdmin发送它和type必须是什么...

有没有办法可以让我type在保存前设置字段?

Chr*_*att 28

Alasdair的答案并没有错,但它有一些可能导致问题的痛点.首先,通过使用form作为变量名称的formset循环,实际上覆盖传递给方法的值form.这不是什么大不了的事,但既然你可以直接从formset中进行保存,那么最好这样做.其次,重要的formset.save_m2m()是被排除在答案之外.实际的Django文档推荐以下内容:

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()
Run Code Online (Sandbox Code Playgroud)

您将遇到的问题是该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)
Run Code Online (Sandbox Code Playgroud)

然后,您不需要对内联执行任何特殊操作.只需更改现有的内联管理类以使用适当的代理模型,一切都将自行排序.


Ala*_*air 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()
Run Code Online (Sandbox Code Playgroud)