How To Properly Customize Django LoginView

12,257

To answer your question, let me suppose you have a client model, in a way, similar to this model, and we'll need a helper models that stores the user's logins:

models.py:

from django.db import models
from django.contrib.auth.models import User

class Client(models.Model):
    """
    This client model is pointing to django's User model
    You can use your custom user model using AbstractBaseUser or whatever.
    And if you're using django's User model directly, this class is not required
    """
    user = models.OneToOneField(
        User,
        on_delete=models.DO_NOTHING,
        verbose_name='User',
        related_name='cli',  # related name manager if needed
        null=False,
        blank=False,
    )

    def __str__(self):
        return '{}'.format(self.user.username)


class ClientLogins(models.Model):
    """
    This is a helper model table that stores the logins dates of the client
    """
    client = models.ForeignKey(
        Client,
        verbose_name='Client',
        on_delete=models.DO_NOTHING
    )
    date = models.DateTimeField(verbose_name="Date login")

    def __str__(self):
        return '{}'.format(self.client)

Then your form:

forms.py:

class LoginForm(forms.ModelForm):
    '''Simple login form'''
    class Meta:
        model = User
        fields = ('username', 'password')

And finally, your login behaviour should be treated in the views classes/functions.

views.py:

from datetime import timedelta
from django.utils import timezone
from MY_APP import models, forms

class LoginUser(LoginView):
    template_name = 'login.html'  # your template
    from_class = forms.LoginForm  # your form

    def get_success_url(self):
        '''Here the part where you can implement your login logic'''
        now = timezone.now()
        # Get current day date object
        # like: 12/02/2019 00:00:00
        today = now.replace(minute=0).replace(second=0).replace(microsecond=0)
        # Get the client from the user object
        client = self.request.user.cli
        # Get all the user today's logins and count them
        client_logins = models.ClientLogins.objects.filter(
            client=client,
            date__gte=today,
            date__lte=today + timedelta(days=1)
        ).count()
        if client_logins < 1:  # Or: if not client_logins:
            # create a login tracker record
            models.ClientLogins.objects.create(
                client=client,
                date=now  # Store the date where the user logged in the website
            )
            return reverse_lazy('FIRST_LOGIN_REDIRECT_URL')
        # Or redirect to: settings.LOGIN_REDIRECT_URL
        return super().get_success_url()

And for more informations, this is the core code of LoginView, like this you can know the MRO list and what you can override to have your desired behaviour.

Share:
12,257
Steve Smith
Author by

Steve Smith

Updated on June 04, 2022

Comments

  • Steve Smith
    Steve Smith almost 2 years

    I am trying to figure out how to customize the django LoginView based on whether or not it's the user's first time logging on for the day. I have my LoginView currently set up so that it defaults to the LOGIN_REDIRECT_URL = "book:author" in my settings.py file. This works flawlessly. When a user logins in and is successfully authenticated, they are redirected to "book:author" as I would expect.

    What I'm trying to do is if this is the first time the user has logged in for the day, direct them to one URL, and if it's any other login iteration for the day, redirect them to a different URL. I have read about various methods on how to do this, to use messaging as opposed to conditional URL redirect to using the NEXT parameter and I'm trying to figure out which is the best and most secure and proper way of going about this.

    Here is my default LoginView...( Nothing fancy )

    class LoginView(LoginView):
        template_name = 'registration/login.html'
        form_class = AuthenticationForm
    

    And then it redirects based on my settings.py file definition...

        LOGIN_REDIRECT_URL = "book:author" 
    

    What is the best way to redirect for first login of the day to different URL?

    Thanks in advance for any suggestions.

    I found this SO answer Django -- Conditional Login Redirect and it seems to be what I'm looking for. Are there any downsides to using the example at the bottom?

    And how to do with a LoginView as opposed to the function based example?