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.
Here is my 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)
Some of the comments suggested using signals. While you can use signals, specifically the m2m_changed
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 ItemMembership
) to know if the associated Order
instance was just created or not.
Sure, you can probably use the cache
framework to set a temporary flag upon calling save()
of an Order
object, then read that same flag on the m2m_changed
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.
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 Order
object with its associated ItemMembership
objects have been successfully created. IMHO, it also makes debugging a lot easier.