Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django m2m_changed with custom through model

In Django I do have two models "Author" and "Publication" that are connected with a Many-to-Many-Field, so that I can assign different authors to a publication. Additionally, I have to use a custom through-model "Authorship" to define the correct order.

class Author(models.Model):
    first_name = models.CharField(max_length=48)
    .....


class Authorship(models.Model):
    author = models.ForeignKey(Author)
    publication = models.ForeignKey('Publication')
    order_of_authorship = models.IntegerField(default=1)


class Publication(models.Model):
    title = models.CharField(max_length=128)
    authors = models.ManyToManyField(Author, through=Authorship)
    year = models.IntegerField(max_length=4)
    ...

    citation_key = models.CharField(max_length=9, blank=True, default="")

At the moment I use the Admin Interface to populate my data with a form for the "Publication" and an inline form "Authorship".

What I want to achieve now: An additional citation_key-field (e.g. "Einstein1950") should be auto-populated after data has changed.

What I tried to do: I found out that using signals must be the best practice.

However the "m2m_changed"-Signal on "Publication.authors.through" is not fired, when I change the Authorships.

@receiver(m2m_changed, sender=Publication.authors.through)
def authors_changed(sender, **kwargs):
    print("authors changed")

This problem is also discussed in a related topic, where the author seems to use "post_save" on the through-model.

@receiver(post_save, sender=Authorship)
def authorship_changed(sender, instance, **kwargs):
    print("authors changed")

This seems to work out, but I have to keep in mind, that a deletion is not covered yet, so I added a post_delete-signal:

@receiver(post_delete, sender=Authorship)
def authorship_deleted(sender, instance, **kwargs):
    print("authors deleted")

The problem now is: If I add 4 authors, I get that event fired 4 times. If I want to update my citation_key as described before, this happens also 4 times.

Can this be the correct solution? Or is there a better best practice? I assume it must work somehow with the m2m_changed signal, but I don't know how. Since I am new to Django, I don't know if this is the obvious solution for you. Furthermore, in this scenario the unnecessary calculation should not have a huge impact, but it is not nice at all.

I only found a really old bug-report in the Django-Trac that seems to address this problem as well. But there is not solution yet.

like image 991
BumbleBee Avatar asked Apr 29 '15 18:04

BumbleBee


Video Answer


1 Answers

This is a known bug, reported as ticket 17688 on Django.

like image 105
bignose Avatar answered Sep 19 '22 14:09

bignose