djangomodelforeign-keys

Django - dynamically update a count model field when related objects are added or removed


I've tried to research this myself but can't figure it out so I'm hoping someone may be able to offer me some direction.

I have the following 2 models:

    class Group(models.Model):
    short_name = models.CharField(max_length=10, primary_key=True)  # company acronym
    full_name = models.CharField(max_length=200)
    learner_count = models.PositiveIntegerField(default=0)
    contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    startDate = models.DateField()
    endDate = models.DateField()
    notes = models.TextField(blank=True, null=True)
    class Learner(models.Model):
    ...
    group = models.ForeignKey(Group, on_delete=models.CASCADE)

Is it possible to update the learner_count field of Group dynamically as learners are added to, or removed from, a group?


Solution

  • Is it possible to update the learner_count field of Group dynamically as learners are added to, or removed from, a group?

    I would advise not to store a Learner count at all. You don't need to store this. Sure, you can work with for example signals to recalculate the count, but signals don't run for all database manipulations, and it is also not easy to catch every situation: what if a Learner changes the group field instead of deleting the learner object. So the problem often gets complicated very easily.

    The model thus looks like:

    class Group(models.Model):
        short_name = models.CharField(
            max_length=10, primary_key=True
        )  # company acronym
        full_name = models.CharField(max_length=200)
        # learner_count = models.PositiveIntegerField(default=0)
        contract = models.ForeignKey(Contract, on_delete=models.CASCADE)
        course = models.ForeignKey(Course, on_delete=models.CASCADE)
        startDate = models.DateField()
        endDate = models.DateField()
        notes = models.TextField(blank=True, null=True)

    You can determine it when necessary with:

    from django.db.models import Count
    
    Group.objects.annotate(learner_count=Count('learner'))

    The Group objects arising from this Queryset will have an extra attribute .learner_count with the number of related Learner records.