Reputation: 103
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
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
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