[Django]-How to add all foreign key relations in Django?

3👍

Instead of making Total_persons a separate field, you can drop the field and simply get the number of Persons belonging to a Country instance country with:

country.person_set.count()

Or if you prefer a friendlier name, you can give the Country foreign key in Person a related_name:

class Person(models.Model):
    Country = models.ForeignKey(Country, related_name='persons', on_delete=models.CASCADE, null=True)

so that you can get the same count with:

country.persons.count()

Or if you’d still prefer to make Total_persons a separate field, you can override the Person.save() method to sync its country when a Person instance is created (when its pk is None), and override the Person.delete() method to sync when Person instance is deleted:

class Person(models.Model):
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.pk:
            self.Country.Total_persons = self.Country.person_set.count()
            self.Country.save()
    def delete(self):
        country = self.Country
        super().delete()
        country.Total_persons = country.person_set.count()
        country.save()

3👍

Your model field names should be lower case.
See Coding Style-Model for more information. Also your population and language fields don’t seem to have the right data type??

Another way to achieve what you need is by using model properties.

class Country(models.Model):
    name = models.CharField(max_length=100)
    population = models.CharField(max_length=100)
    language = models.IntegerField()

    @property
    def total_people(self):
        return self.people.count()

class Person(models.Model):
    Country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True,
                                related_name='people')
    name = models.CharField(max_length=100)
    contact = models.IntegerField()
👤Angela

2👍

You have several ways to have the number of people in countries without a DB field:

With annotations:

qs = Country.objects.annotate(total_people=models.Count('person_set'))
for country in qs:
    print(country.total_people)

Else if you really want to have a DB field, you can use post/pre hooks.
There are:

  • Post save

    @receiver(post_save, sender=Person)
    def increment_total_people(sender, instance, created, **kwargs):
        instance.Country.Total_persons += 1
        instance.Country.save()
    
  • Post delete

    @receiver(post_delete, sender=Person)
    def decrement_total_people(sender, instance, **kwargs):
        instance.Country.Total_persons -= 1
        instance.Country.save()
    

But you’ll have to design things for all use cases when this number could change.

👤Zulu

Leave a comment