djangodjango-modelsdjango-admindjango-admin-toolsdjango-admin-actions

Django - Apply model on many (1000's) foreign key objects in admin


I have a model of a football coach and a model of a membership payment which has a foreign key to the coach model.

In the admin, I want to be able to apply the membership to a lot of coaches at once and not only to one coach. In essence, I imagine a raw_id field which is selectable.

The coach has a field balance and the membership model deducts on save some amount from that field of the coach.

Is something like this possible?

Here are my models:

class Coach(models.Model):
    class Meta:
        verbose_name = 'Coach'
        verbose_name_plural = 'Coaches'



    last_name = models.CharField(max_length=100) #new
    name = models.CharField(max_length=100)

    balance = models.IntegerField() #new


    def __str__(self):
        return str(self.last_name)

and my membership model:

class Membership(models.Model):
    class Meta:
        verbose_name = 'Membership'
        verbose_name_plural = 'Memberships'

    coach = models.ForeignKey(Coach, on_delete=models.CASCADE)
    date_of_transaction = models.DateField()
    description = models.CharField(max_length = 200, blank=True, null=True)
    amount = models.IntegerField( verbose_name="amount (enter positiv integer)")

    # @property
    # def payment(self):
    #     self.coach.balance -= self.amount
    #     self.coach.save()
    #     return 

    def save(self, *args, **kwargs):
       self.coach.balance -= self.amount
       self.coach.save()
       super(Membership, self).save(*args, **kwargs)

Thank you very much in advance! I am new to django and am not really sure if I created my models in the right way!

Any help or suggestion is highly appreciated!

I tried with many-to-many fields and inline style, as well as with raw_id fields, but I cant get it to work.

Basically, I want to apply the membership which deducts a certain amount to many coaches at once. Ideally, I want to be able to select the coaches and deduct an amount from their balance field.


Solution

  • 1- You can use ManyToManyField for adding coaches to same membership object.

    2- You can use django actions to achieve your aim.

    in models.py:

    class Membership(models.Model):
        class Meta:
            verbose_name = 'Membership'
            verbose_name_plural = 'Memberships'
    
        coaches = models.ManyToManyField(Coach)
        date_of_transaction = models.DateField()
        description = models.CharField(max_length = 200, blank=True, null=True)
        amount = models.IntegerField( verbose_name="amount (enter positiv integer)")
    

    in admin.py:

    @admin.register(models.Membership)
    class MembershipAdmin(admin.ModelAdmin):
        actions = ['make_deduction']
        filter_horizontal = ('coaches', )
        
        @admin.action(description='Make payment deduction from the coaches of selected memberships')
        def make_deduction(self, request, queryset):
            for membership in queryset:
                for coach in membership.coaches.all():
                    coach.balance -= membership.amount
                    coach.save()
    

    filter_horizontal allows you to filter coaches, to select multiple coaches and to add them to membership.

    You are at view of the membership list page:

    deduction is realized.