1

I'd like to update the value of balance of people that are involved in a transaction (creditor and debitors) as soon as I save the transaction (from admin). Here's my models:

#models.py
class Person(models.Model):
    first_name = models.CharField(max_length = 30) 
    last_name = models.CharField(max_length = 30) 
    phone_number = models.CharField(max_length = 30) 
    email = models.EmailField('e-mail')
    balance = models.DecimalField(max_digits = 5, decimal_places = 2)

class Transaction(models.Model):
    creditor = models.ForeignKey(Person,related_name = 'creditor')
    debtors = models.ManyToManyField(Person, related_name = 'debtors')
    value = models.DecimalField(max_digits = 5, decimal_places = 2)
    split = models.BooleanField()
    date = models.DateField()

Here's what I thought about, but I only works when the transaction is beeing changed (does not work for the first time save):

#admin.py
class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name','last_name','balance')

class TransactionAdmin(admin.ModelAdmin):
    list_display = ('creditor','value','date')
    list_filter = ('date',)
    date_hierarchy = 'date'
    ordering = ('-date',)
    filter_horizontal = ('debtors',)

    def save_model(self,request,obj,form,change):
            obj.save()
            if obj.split:
                    split_value = obj.value/(obj.debtors.all().count()+1)
                    for debtor in obj.debtors.all():
                            p = Person.objects.get(id = debtor.id)
                            p.balance = p.balance - split_value
                            p.save()
                    p = Person.objects.get(id = obj.creditor.id)
                    p.balance = p.balance + (obj.debtors.all().count())*split_value                     
                    p.save()

admin.site.register(Person,PersonAdmin)
admin.site.register(Transaction,TransactionAdmin)

I'm new to Django and really confused about the proper way of doing this. I'd appreciate any help on this.

Bruno Calza
  • 2,732
  • 2
  • 23
  • 25

2 Answers2

0

You can use django's signals so create a function that is (synchronously) fired once your save has been carried out (a post-save function to be precise).

So for example:

from django.db.models.signals import post_save
from signals import do_something

class TransactionAdmin(models.Model):
    ...

post_save.connect(do_something, sender=TransactionAdmin)

and in a signals.py file:

def do_something(sender, instance, created, *args, **kwargs):
    if created and sender == TransactionAdmin:
        ...
    ...
Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
0

Here's the solution that I found after studying these links:

  1. https://docs.djangoproject.com/en/dev/ref/contrib/admin/
  2. http://reinout.vanrees.org/weblog/2011/11/29/many-to-many-field-save-method.html
  3. Issue with ManyToMany Relationships not updating inmediatly after save
  4. Django manytomany signals?
  5. http://python.6.n6.nabble.com/Process-Related-Object-when-Saving-td4974737.html

   def save_related(self,request,form,formsets,change):
            form.save_m2m()

            debtors = form.instance.debtors.all()
            n_debtors = debtors.count()
            creditor = form.instance.creditor
            value = form.instance.value

            if form.instance.split:
                    value = value/(n_debtors + 1)

            for debtor in debtors:
                    p = Person.objects.get(id = debtor.id)
                    p.balance = p.balance - value
                    p.save()

            p = Person.objects.get(id = creditor.id)    
            p.balance = p.balance + n_debtors*value
            p.save()
Community
  • 1
  • 1
Bruno Calza
  • 2,732
  • 2
  • 23
  • 25