Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override save on Django InlineModelAdmin

Tags:

That question might look similar to this one, but it's not...

I have a model structure like :

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

I am using InlineModels, and have two types of CustomerCompany.type. So I define two different inlines for the CustomerCompany and override 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)      

All is nice and good up to here, but for adding new records for InlineModelAdmin, I still need to display type field of CustomerCompany on the AdminForm, since I can not override save method of an InlineModelAdmin like:

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() 

Using a signal is also not a solution since my signal sender will be the same Model, so I can not detect which InlineModelAdmin send it and what the type must be...

Is there a way that will let me set type field before save?

like image 966
FallenAngel Avatar asked Nov 28 '11 11:11

FallenAngel


People also ask

How do I override a save in Django?

save() method from its parent class is to be overridden so we use super keyword. slugify is a function that converts any string into a slug. so we are converting the title to form a slug basically.

How do I save models in Django?

Creating objects To create an object, instantiate it using keyword arguments to the model class, then call save() to save it to the database. This performs an INSERT SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() . The save() method has no return value.


2 Answers

Alasdair's answer isn't wrong, but it has a few sore points that could cause problems. First, by looping through the formset using form as the variable name, you actually override the value passed into the method for form. It's not a huge deal, but since you can do the save without commit right from the formset, it's better to do it that way. Second, the all important formset.save_m2m() was left out of the answer. The actual Django docs recommend the following:

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() 

The problem you're going to run into is that the save_formset method must go on the parent ModelAdmin rather than the inlines, and from there, there's no way to know which inline is actually being utilized. If you have an obj with two "types" and all the fields are the same, then you should be using proxy models and you can actually override the save method of each to set the appropriate type automatically.

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) 

Then, you don't need to do anything special at all with your inlines. Just change your existing inline admin classes to use their appropriate proxy model, and everything will sort itself out.

like image 66
Chris Pratt Avatar answered Oct 16 '22 04:10

Chris Pratt


There's a save_formset method which you could override. You'd have to work out which inline the formset represents somehow.

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() 
like image 36
Alasdair Avatar answered Oct 16 '22 06:10

Alasdair