You are not logged in.

Change Language:

Freelancer? Consultant? Check out: WorkTrail - Time Tracking made easy
Board » Django Standard Library » Admin » save() method of a BaseModelFormSet object not called

Hi there!

I have created a custom model formset class which inherits from the BaseModelFormSet class:
class WeeklyPlaylistAdminFormSet(BaseModelFormSet):
    def save(self, commit=True):
        instances = super(WeeklyPlaylistAdminFormSet, self).save_existing_objects(commit)

        do_something_with_instances(instances)

        return instances


which is then used in a custom ModelAdmin class:

class WeeklyPlaylistAdmin(admin.ModelAdmin):
    list_display = (schedule_video_name, schedule_screen_name, schedule_year, 'week', 'position', 'position_link')
    list_editable = ('position',)
    
    def get_changelist_formset(self, request, **kwargs):
        return modelformset_factory(self.model,
                        self.get_changelist_form(request), extra=0,
                        fields=self.list_editable,
                        formset=WeeklyPlaylistAdminFormSet)


However, the problem is that the save() method of the WeeklyPlaylistAdminFormSet does not seem to be called at all, for a reason which I don't understand, even though the objects displayed in the change_list page of the WeeklyPlaylistAdmin class are modified when I change one of the fields in the editable fields. Did I miss something in the way the save() method has to be overriden? Or is there another save_*() method which I should override instead? I've seen that there are several other methods in the BaseModelFormSet class (from django.forms.models): save_existing(), save_existing_objects()... I've tried few of these but it didn't make any difference, and they were not called either...

What's even more surprising is that I've also overriden the clean() of the BaseModelFormSet class and it seems to be called correctly... Only the save method is a problem...

Any suggestion?

Adrien
Hi,
Is possibile for you overload model save method ? This is the simply way...
Your overload of get_changelist_formset is correctly done:
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L492

The overload of BaseModelFormSet probably also correct.
https://code.djangoproject.com/browser/django/trunk/django/forms/models.py#L412

To understand if the save method is run you running put in an exception.
Ex:
class WeeklyPlaylistAdminFormSet(BaseModelFormSet):
    def save(self, commit=True):
        instances = super(WeeklyPlaylistAdminFormSet, self).save_existing_objects(commit)
        raise Exception('TEST')
        do_something_with_instances(instances)

        return instances

Make me know if you find the solution.

// Robin

--- Last Edited by arwa at 2012-01-26 00:56:19 ---
Thanks for your reply, Robin, I've tried what you said and it confirmed that the save method is not called: when I click on the save button of the change_list page, the modified objects are saved but the exception is not raised! Why is it that the save method does not seem to be called while the clean method works fine?

Adrien
One question: which is your django version?
It's 1.3.1
I don't know what you want to do, but a solution to intercept save in admin is to overload save_model of Admin class
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L705
Ex:
class WeeklyPlaylistAdmin(admin.ModelAdmin):
  def save_model(self, request, obj, form, change):
    # do something
    return obj.save() # this call the save model method


Is possibile also work on model:
https://code.djangoproject.com/browser/django/trunk/django/db/models/base.py#L453
Ex:
class WeeklyPlaylist(models.Model):
  ...
    def save(self,*args,**kwargs):
      obj = super(self.__class__,self).save(*args, **kwargs)
      # do something
      return obj

I hope that one of these two solution can help you.

// Robin
Thanks Robin, the 'save_model' method is being called, so I could potentially use that one, but what I'd like to do is some sort of cross checking between all the modified objects of the queryset. Maybe I should give more details about the model first:
class WeeklyPlaylist(models.Model):
	total_num_entries_in_playlist = 8
	get_pos_choices = get_integer_choices(1, total_num_entries_in_playlist)

	sched = models.ForeignKey(Schedule)
	week = models.IntegerField(choices=get_integer_choices(1, 52))
	position = models.IntegerField(choices=get_pos_choices)


where 'position' simply indicates the position of a video in a playlist: I'd like to make it possible for the admin to swap the 'position' value of 2 objects of the query set, which implies doing some cross validation to ensure the new position matches an existing object in the queryset (or in the database) and then do the swapping operation.
Now I understand why you want a global validation of all change_list instance. :-)
I have no idea why your method not works.
If I have a moment I'm trying to understand better this problem....

Little suggestion: I like this code for field choices.
position = models.IntegerField(choices=[(i,str(i) for i in range(1,9)])


// Robin

--- Last Edited by arwa at 2012-01-26 04:05:32 ---
Thanks for your help and suggestion, Robin, looking forward to hearing from you with the solution to my problem ;)

Adrien





Powered by Sphene Community Tools