Django: Custom Save method for Many-to-Many relation

余生颓废 提交于 2019-12-06 10:53:25

问题


I need to set custom save and delete methods on a Many-to-Many relation.

I tried specifying a model with the "through" attribute but this over-complicated my code and introduced some problems. I don't need any extra field on the Many-to-Many model, just custom save and delete methods.

Is it possible to accomplish this without specifying the "through" attribute?

Here's code:

class Order(BaseDate):
    #lots of fields
    relateds = models.ManyToManyField('RelatedProduct', verbose_name=_('related products'), blank=True, related_name='order_relateds', through='OrderRelateds')
    # more fields
    total = CurrencyField(verbose_name=_('total'))

    def calculate_total(self):
        cleanses = self.cleanse.taxed_price() * self.quantity
        delivery = DELIVERY_PRICE if self.delivery == 'delivery' else 0
        relateds = 0
        for r in self.relateds.all():
            relateds = relateds + float(r.taxed_price())
        total = float(cleanses) + delivery + relateds
        return total

    def save(self, *args, **kwargs):
        self.total = '%.2f' % self.calculate_total()
        super(Order, self).save(*args, **kwargs)

class OrderRelateds(models.Model):
    order = models.ForeignKey(Order)
    relatedproduct = models.ForeignKey(RelatedProduct, verbose_name=_('related product'))

    class Meta:
        verbose_name = _('Related Product')
        verbose_name_plural = _('Products Related to this Order')

    def __unicode__(self):
        return self.relatedproduct.__unicode__()

    def save(self, *args, **kwargs):
        super(OrderRelateds, self).save(*args, **kwargs)
        self.order.save()

    def delete(self, *args, **kwargs):
        super(OrderRelateds, self).delete(*args, **kwargs)
        self.order.save()

I need to trigger recalculation of total price of the order if any related product (many to many item) is added to or removed from an order.

Edit: this is the code which solved my problem

from django.db.models.signals import m2m_changed
from django.dispatch import receiver

@receiver(m2m_changed, sender=Order.relateds.through)
def recalculate_total(sender, instance, action, **kwargs):
    """
    Automatically recalculate total price of an order when a related product is added or removed
    """
    if action == 'post_add':
        instance.save()
    if action == 'post_remove' or action == 'post_clear':
        instance.save()

回答1:


You could make use of django's m2m_changed, pre_save/post_save, pre_delete/post_delete signals on the Model containing the relation, and do the related logic there.




回答2:


Timmy's answer is definitely correct and works. For your special case however, I am wondering, if you should not handle that logic in the view, where you manage the order and order items and enforce the recalculation there, since the adding, editing and deleting of order items all belong together and belong to the order.



来源:https://stackoverflow.com/questions/11988946/django-custom-save-method-for-many-to-many-relation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!