On brand with the python groove I have been in, I thought it would be neat to have a simple user log in/registration with validations in my arsenal.

I put the log in/validation in a simple post/message board application I built using python/django and used bcrypt to encrypt user passwords.

First I created my models.

(models.py)

class User(models.Model):
    first_name = models.CharField(max_length=45)
    last_name = models.CharField(max_length=45)
    email = models.CharField(max_length=255)
    password = models.CharField(max_length=45)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    objects = UserManager()


class Message(models.Model):
    user = models.ForeignKey(User, related_name="messages", default=None, on_delete=models.CASCADE)
    message_text = models.CharField(max_length=255, default=None)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class Comment(models.Model):
    comment_text = models.CharField(max_length=255, default=None)
    messages = models.ForeignKey(Message, related_name="comments", default=None, on_delete=models.CASCADE)
    users = models.ForeignKey(User, related_name="comments", default=None, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

after that, I created my UserManager which housed my validators

(models.py)

class UserManager(models.Manager):
    def basic_validator(self, postData):
        EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+$')
        errors = {}
        if len(postData['first_name']) < 2:
            errors['first_name'] = "First name should be at least 2 characters long!"
        if len(postData['last_name']) < 2:
            errors['last_name'] = "Last name should be at least 2 characters long!"
        if User.objects.filter(email=postData['email']).exists():
            errors['email'] = "Email should be unique!"
        if not EMAIL_REGEX.match(postData['email']):  # test whether a field matches the pattern
            errors['email_makes_sense'] = "Invalid email address!"
        if len(postData['password']) < 8:
            errors['pw_length'] = "Passwords should be at least 8 characters long!"
        if postData['password'] != postData['password_confirm']:
            errors['pw_confirm'] = "Your passwords need to match!"
        return errors

    def basic_validator2(self, postData):
        EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+$')
        errors = {}
        if not User.objects.filter(email=postData['email']).exists():
            errors['email'] = "Email not in db!"
        if not EMAIL_REGEX.match(postData['email']):  # test whether a field matches the pattern
            errors['email_makes_sense'] = "Invalid email address!"
        this_user = User.objects.get(email=postData['email'])
        check_it = bcrypt.checkpw(postData['password'].encode(), this_user.password.encode())
        if check_it is False:
            errors['password'] = "you typed the wrong password!"
        return errors

Made sure to create some simple and descriptive url paths to use on the front end

(urls.py)

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
    path('register_user', views.register_user),
    path('login', views.login),
    path('wall', views.wall),
    path('logout', views.logout),
    path('post_message', views.post_message),
    path('post_comment', views.post_comment),
    path('delete_message', views.delete_message),
]

Finally, I hooked up my urls to their views

(views.py)

def index(request):
    return render(request, 'index.html')


def register_user(request):
    errors = User.objects.basic_validator(request.POST)
    if len(errors) > 0:
        for key, value in errors.items():
            messages.error(request, value)
        return redirect('/')
    else:
        hash1 = bcrypt.hashpw(request.POST['password'].encode(), bcrypt.gensalt()).decode()
        print(hash1)
        c = User.objects.create(first_name=request.POST['first_name'], last_name=request.POST['last_name'],
                                email=request.POST['email'], password=hash1)
        c.save()
        request.session['this_user'] = c.id
        request.session['right_message'] = "Successfully created a new account!"
        return redirect('/wall')


def login(request):
    errors = User.objects.basic_validator2(request.POST)
    if len(errors) > 0:
        for key, value in errors.items():
            messages.error(request, value)
        return redirect('/')
    else:
        getting_something = User.objects.get(email=request.POST['email'])
        request.session['this_user'] = getting_something.id
        request.session['right_message'] = "Successfully logged in!"
        return redirect('/wall')


def wall(request):
    this_message = request.session['right_message']

    context = {
        'users': User.objects.all(),
        'user': User.objects.get(id=request.session['this_user']),
        'message': this_message,
        'message_list': reversed(Message.objects.all())
    }
    return render(request, 'wall.html', context)


def logout(request):
    request.session.flush()
    return redirect('/')


def post_message(request):
    c = Message.objects.create(user_id=request.session['this_user'], message_text=request.POST['message_content'])
    c.save()
    return redirect('/wall')

def post_comment(request):
    c = Comment.objects.create(messages_id=request.POST['post_it'], users_id=request.session['this_user'], comment_text=request.POST['comment_content'])
    c.save()
    return redirect('/wall')

def delete_message(request):
    this_message = request.POST['delete_it']
    c = Message.objects.get(id=this_message)
    c.delete()
    return redirect('/wall')