ManyToManyField в общих представлениях на основе классов и переопределении сохранения

У нас есть общее представление на основе классов, которое добавляет объект с отношением ManyToManyField. Мы пытаемся изменить некоторые значения переопределения save() для отношений, созданных в этом ManyToManyField, но похоже, что они никогда не создаются в save(), поэтому мы вынуждены вызывать метод post_save в get_success_url, поэтому отношения создаются. Это кажется очень, очень некрасивым. Как заставить отношения создаваться до того, как мы покинем save()?

Я видел этот ответ на SO, в котором сказано переопределить form_valid() для создания отношений, но зачем мне это делать, если они создаются автоматически где-то между form_valid() и get_success_url()?

# models.py
class Payment(models.Model):
    invoice = models.ManyToManyField(Invoice)
    deposit_date = models.DateField()
    check_number = models.CharField(max_length=100, blank=True, null=True)
    description = models.TextField(blank=True, null=True)

    def post_save(self):
        """
        ManyToManyField relationships aren't formed yet when overriding save() for Class Based Generic
        Views. Call this whenever you're saving a Payment object.
        """
        for invoice in self.invoice.all():
            # Do some calcualtions that make us happy
            invoice.save()

# views.py - We override get_success_url() in UpdateView too.
class PaymentAdd(CreateView):
    model = Payment
    form_class = PaymentForm
    context_object_name = 'object'
    template_name = 'form.html'

    def get_success_url(self):
        self.object.post_save()
        return reverse('payment-page')

person scoopseven    schedule 09.05.2013    source источник


Ответы (1)


Если это необходимо делать каждый раз при сохранении Payment, лучше возложить эту ответственность на модель, а не перемещать ее в режим просмотра. Лучше всего использовать сигнал post_save примерно так:

В models.py, где-то ниже определения модели Payment:

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

@receiver(post_save, sender=Payment)
def my_handler(sender, instance, **kwargs):
    for invoice in instance.invoice.all():
        # Do some calcualtions that make us happy
        invoice.save()

Кстати, я настоятельно рекомендую вам использовать имена атрибутов во множественном числе для полей M2M: в данном случае invoices вместо invoice. Это делает его намного более понятным для ваших коллег-разработчиков.

person Berislav Lopac    schedule 11.05.2013