-2

We do not use Date of Birth as a mandatory field during signup. But, in the Model we have an auto-calculate function to arrive at the 'Age' of the user.

So while this works fine when using Django built-in registration mechanism, it fails with custom.

How can Signals be leveraged to check -

  1. if DoB was entered?
  2. if DoB entered, then calculate Age and Populate Age Field?

Thanks in Advance for shring your knowledge.

Regds.

  • Please *don't* use signals for this. Exactly what is not working with your custom registration? – Willem Van Onsem Aug 01 '21 at 09:11
  • @WillemVanOnsem this signal works fine. Thank you for your wisdom. Signals is the way to have a clean code. Maybe you want to copy??! – Feramonics Aug 03 '21 at 01:02
  • ```Signals.py``` is used to de-code and create ***events** based action. Use the code. – Feramonics Aug 03 '21 at 01:38
  • here is a list of all problems that arise with signals: https://www.django-antipatterns.com/antipattern/signals.html – Willem Van Onsem Aug 03 '21 at 10:41
  • @WillemVanOnsem I understand where you are comming from. But the process of creation of users should ideally __not be__ a bulk activity. And thank you for sharing. Will keep it mind. – Feramonics Aug 04 '21 at 08:35
  • it is not only about bulk_creates, it is also about getting in an infinite loop, unexpected exceptions (typically resolved with a blanket catch, which is an anti-pattern by itself), delay between creating a user, and linking a profile for example. See for example https://lincolnloop.com/blog/django-anti-patterns-signals/ and https://www.quora.com/Are-Django-signals-an-anti-pattern It also violates the [*Zen of Python*](https://www.python.org/dev/peps/pep-0020/) that explicit is better than implicit. – Willem Van Onsem Aug 04 '21 at 08:38

2 Answers2

0

Use this.


    if instance.dateBirth:
        
        today = date.today()
        rdelta = relativedelta(today,instance.dateBirth)
        instance.Age = rdelta.years

        if instance.Age > 18: #timedelta(days=18 * 365):

            instance.is_adult = True

            return(instance.is_adult, instance.Age)
        else:
            instance.is_adult = False

            return (instance.is_adult, instance.Age)

dont forget to update __init__.py and apps.py

0

Storing the age in a field looks like a bad idea: if the record is not updated somehow, or the signals do not run, then the age can get outdated. For example a person might be stored in the database, but if you never save that object again, after the person's birthday, it will still show the old age.

Therefore it is better not to store this in a field, and use for example a property to determine this when that is necessary, you can define such model with:

from django.utils.timezone import now

class User(models.Model):
    # …
    date_of_birth = models.DateField()
    # no age or is_adult field

    @property
    def age(self):
        today = now().date()
        dob = self.date_of_birth
        return today.year - dob.year - (today.timetuple()[1:3] < dob.timetuple()[1:3])
    
    @property
    def is_adult(self):
        return self.age >= 18

This will thus make it possible to access .age and .is_adult for a User object.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555