Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django admin save not sending post_remove action with m2m_changed signal

Tags:

django

m2m

I'm trying to get a many to many model to update when I save a related model. This should be possible using the m2m_changed signal (and it works! but not in the admin?) e.g.

# i want the references field to update when related model is saved.
# so just call count_references

class Tag(models.Model):
    """Group everything into categories"""
    # stuff stuff stuff
    references = models.IntegerField(default=0, editable=False)

    def count_references(self):
        # just add up references each time to save headaches
        self.references = 0
        # search for reverse managers
        sets = re.compile('^\w+_set$')
        for rel_set in [method for method in dir(self) if sets.match(method)]:
            self.references += getattr(self, rel_set).count()
        self.save()

class Entry(models.Model):
    """Blog entry"""
    # stuff stuff stuff
    tags = models.ManyToManyField('Tag', blank=True)

# this will call count_references when entry adds or removes tags

@receiver(m2m_changed, sender=Entry.tags.through)
def update_tag_ref_count(sender, instance, action, reverse, model, pk_set, **kwargs):
    print action
    if not reverse and action == 'post_add' or action == 'post_remove':
        for tag_pk in pk_set:
            print tag_pk
            Tag.objects.get(pk=tag_pk).count_references()
            print Tag.objects.get(pk=tag_pk).references

Everything works perfectly when run in the shell. e.g. with a tests.py like so:

t = Tag.objects.all()[0]
s = Snippet.objects.all()[0]

s.tags.remove(t)
s.save()

s.tags.add(t)
s.save()

I get the following (where 'test' is the tag name being printed):

pre_remove
post_remove
test
0
pre_add
post_add
test
1

perfect! And when I add a tag to an entry in the admin I get the following (between HTTP stuff):

pre_clear
post_clear
pre_add
post_add
test
1

still good! not sure what pre/post_clear was called for... and when I remove:

pre_clear
post_clear

argh! pre/post_remove is not called! pre/post_clear is useless as well as it doesn't provide any primary keys. this feels like a bug in the admin implementation. any suggestions?

Update: Bug #16073 filed and accepted.

like image 766
Sam Simmons Avatar asked May 23 '11 03:05

Sam Simmons


1 Answers

(Creating this as a community wiki to close out this as an "unanswered" question.)

This is a bug in Django. OP filed a ticket at https://code.djangoproject.com/ticket/16073.

like image 125
Chris Pratt Avatar answered Sep 19 '22 23:09

Chris Pratt