Access m2m relationships on the save method of a newly created instance
<p>I'd like to send emails (only) when Order instances are created. In the email template, I need to access the m2m relationships. Unfortunatly, its seems like the m2m relations are ont yet populated, and the itemmembership_set.all() method returns an empty list.</p>

<p>Here is my code:</p>

<pre><code>class Item(models.Model):
   ...

class Order(models.Model):
    ...
    items = models.ManyToManyField(Item, through='ItemMembership')

    def save(self, *args, **kwargs):
        pk = self.pk

        super(Order, self).save(*args, **kwargs)

        # If the instance is beeing created, sends an email with the order
        # details.
        if not pk:
            self.send_details_email()

    def send_details_email(self):
        assert len(self.itemmembership_set.all()) != 0

class ItemMembership(models.Model):
    order = models.ForeignKey(Order)
    item = models.ForeignKey(Item)
    quantity = models.PositiveSmallIntegerField(default=1)
</code></pre>

<p>Some of the comments suggested using signals. While you can use signals, specifically the <code>m2m_changed</code> signal, this will always fire whenever you modify the m2m fields. As far as I know, there is no way for the sender model (in your sample, that is <code>ItemMembership</code>) to know if the associated <code>Order</code> instance was just created or not.</p>

<p>Sure, you can probably use the <code>cache</code> framework to set a temporary flag upon calling <code>save()</code> of an <code>Order</code> object, then read that same flag on the <code>m2m_changed</code> signal and delete the flag when it is over. The downside is you have to validate the process, and it beats the purpose of using signals which is to decouple stuff.</p>

<p>My suggestion is to totally remove all those email sending functionalities from your models. Implement it as a helper function instead, and then just invoke the helper function explicitly after an <code>Order</code> object with its associated <code>ItemMembership</code> objects have been successfully created. IMHO, it also makes debugging a lot easier.</p>

python django django-models m2m