jakebake
jakebake

Reputation: 103

How do I validate that a user is at least 13 years old?

I have created a login and registration app in Python for use with Django and I have been using it in a few different projects. My only problem trying to apply it to some projects is I can't figure out how to make sure a user can only register if they are at least 13 years old.

This is my models.py and what I have imported for the validations.

from django.db import models
from datetime import date, datetime
import re
import bcrypt

class User(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.CharField(max_length=150)
    birthday = models.DateField()
    password = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    objects = UserManager()

This is the only validation I have accompanying the birthday input so far. I have other validations, but this is the only one pertaining to birthday.

def registration_validator(self, post_data):
    errors = {}
    user_birthday = datetime.strptime(post_data['birthday'], '%Y-%m-%d')
        if user_birthday > datetime.today():
            errors["release_date"] = "User birthday must be in the past!"
        return errors_login

My views.py that handles processing the registration.

def process_registration(request):
    errors = User.objects.registration_validator(request.POST)
    if len(errors) > 0:
        for key, value in errors.items():
            messages.error(request, value, extra_tags='register')
        return redirect('/')
    else:
        first_name = request.POST['first_name']
        last_name = request.POST['last_name']
        email = request.POST['email']
        birthday = request.POST['birthday']
        pw_hash = bcrypt.hashpw(request.POST['password'].encode(), bcrypt.gensalt()).decode()
        User.objects.create(first_name=first_name, last_name=last_name, email=email, birthday=birthday, password=pw_hash)
        return redirect(f'/success/{first_name}')

I have an idea of how to convert a birthday input to a usable strptime as I have for the only validation, but I just get lost trying to go further and make sure the user is at least 13.

Upvotes: 0

Views: 326

Answers (2)

Dylan
Dylan

Reputation: 292

You could add a validator to a form field. Then integrate that form into your views.py function.

Many ways to do this, but here is a one simple type of implementation (note this also delegates the password hashing logic to a method in the forms.py class - should be double checked):

views.py

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

from users.forms import UserForm


@csrf_exempt
def process_registration(request):
    try:
        form = UserForm(request.POST)
        if not form.is_valid():
            return HttpResponse(f'bad: {form.errors}')
        form.save()
        return HttpResponse('ok')
    except Exception as e:
        return HttpResponse(f'bad: {e}')

forms.py

from django import forms
from django.core.exceptions import ValidationError
from django.utils import timezone

from dateutil.relativedelta import relativedelta
import bcrypt

from users.models import User


def validate_is_older_than_thirteen(value):
    cutoff_date = timezone.now().date() - relativedelta(years=13)
    if value > cutoff_date:
        raise ValidationError('date is in the future')


class UserForm(forms.ModelForm):
    birthday = forms.DateField(validators=[validate_is_older_than_thirteen])

    def clean_password(self):
        raw_password = self.cleaned_data['password']
        return bcrypt.hashpw(raw_password.encode(), bcrypt.gensalt()).decode()

    class Meta:
        model = User
        fields = '__all__'

Depending on your routes, here is a cURL to test this logic:

curl --request POST \
  --url http://127.0.0.1:8000/register/ \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data first_name=John \
  --data last_name=Doe \
  --data [email protected] \
  --data password=s3kr1t \
  --data birthday=2015-01-01

Upvotes: 0

Tim Nyborg
Tim Nyborg

Reputation: 1649

You can use relativedelta from the dateutils package to add/subtract from today's date:


from dateutil.relativedelta import relativedelta

def age_validator(self, post_data):
    errors = {}
    user_birthday = datetime.strptime(post_data['birthday'], '%Y-%m-%d')
        if user_birthday > datetime.today() - relativedelta(years=13):
            errors["release_date"] = "User must be at least 13"
        return errors_login

Upvotes: 1

Related Questions