9

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.

Community
  • 1
  • 1
BumbleBee
  • 986
  • 9
  • 19
  • Did you find a solution? – François Constant Sep 20 '16 at 02:07
  • No, I didn't find a better solution and this solution works as far as I can see (although it is not perfect). A colleague suggested to create the key in the form with JavaScript, for example in a hidden field. This might be a better solution if you can be sure that you use that in every form that makes changes to the particular fields. – BumbleBee Sep 26 '16 at 06:59
  • Thanks for getting back to me. Too bad. I've used a timestamp (to avoid 4 updates in a row) - far from perfect - similar to your solution but purely backend. – François Constant Sep 26 '16 at 07:57
  • There is also this open bug "No m2m_changed signal sent to when referenced object is deleted" : https://code.djangoproject.com/ticket/17688 – Daviddd Dec 22 '16 at 13:54

1 Answers1

1

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

bignose
  • 30,281
  • 14
  • 77
  • 110