Django Login/Logout System Part-I
Tags: python, django, webdev, codenewbie
Published: 2021-08-27 14:08:04

Hey guys, how have you been? In today's part we are going to create the login system with a **remember me cookie option**

------------------------------------------------------------------

Here again, we don't have to reinvent the wheel thanks for the built in django's authentication system. We can build our authentication system by extending from that and customize it to meet our needs.

Django gives this authentication support in its module `django.contrib.auth` whose configuration is already included in *settings.py* when we created our project in the very beginning. This built in auth app gives us **login, and logout views** together with other password management views that we will go over in later parts of the series.

- Great. Now let's see how we can put all this together.

******************************************************************
Let's start from the login form. Django has a built in `AuthenticationForm` which is a base class for authenticating users based on username and password. 

- We will create our login from by extending from it to add a remember me checkbox, and also bootstrapify the username and password fields using **widgets** as we saw in the previous posts.

- A remember me option is a nice to have feature since users don't want to fill in credentials every time they visit a site.

forms.py
```python
# Add this to previous list of imports
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm 


class LoginForm(AuthenticationForm):
    username = forms.CharField(max_length=100,
                               required=True,
                               widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                             'class': 'form-control',
                                                             }))
    password = forms.CharField(max_length=50,
                               required=True,
                               widget=forms.PasswordInput(attrs={'placeholder': 'Password',
                                                                 'class': 'form-control',
                                                                 'data-toggle': 'password',
                                                                 'id': 'password',
                                                                 'name': 'password',
                                                                 }))
    remember_me = forms.BooleanField(required=False)

    class Meta:
        model = User
        fields = ['username', 'password', 'remember_me']
```
- We have seen how forms are created in the last part when we created the sign up form so we won't go much into detail here.

Next, let's set up the view to use the login form we created. Django also has a built in [LoginView](https://docs.djangoproject.com/en/3.2/topics/auth/default/#django.contrib.auth.views.LoginView). We can override some of the class's attributes and methods to meet our needs.

views.py
```python
from django.contrib.auth.views import LoginView
from .forms import RegisterForm, LoginForm

# Class based view that extends from the built in login view to add a remember me functionality
class CustomLoginView(LoginView):
    form_class = LoginForm

    def form_valid(self, form):
        remember_me = form.cleaned_data.get('remember_me')

        if not remember_me:
            # set session expiry to 0 seconds. So it will automatically close the session after the browser is closed.
            self.request.session.set_expiry(0)

            # Set session as modified to force data updates/cookie to be saved.
            self.request.session.modified = True

        # else browser session will be as long as the session cookie time "SESSION_COOKIE_AGE" defined in settings.py
        return super(CustomLoginView, self).form_valid(form)
```

- The first thing we did is set the `form_class` attribute to our custom `LoginForm` since we are no longer using the default `AuthenticationForm`. 

- Next we overrode the `form_valid` method which is called when valid form data has been posted. Inside this method we checked to see whether or not the remember_me check box is checked (a lot of "checks" there, am having a tongue twister:) ). 

- If it's not checked, session will expire automatically when the browser is closed. But for the users who check on the remember_me box, the session will last as long as we define it in *settings.py*.
- So let's go ahead and set the `SESSION_COOKIE_AGE` to 30 days (or as long as you want it to last) in the settings.

settings.py
```python
SESSION_COOKIE_AGE = 60 * 60 * 24 * 30
```

- Great. Now inside our main project's *urls.py* let's map the desired login route to the corresponding *CustomLoginView*.
- While we are at it, let's also create the logout route which will be handled by the built in `LogoutView`.

user_management/urls.py
```python
# Add the following to the list of previous imports
from django.contrib.auth import views as auth_views
from users.views import CustomLoginView  
from users.forms import LoginForm

urlpatterns = [
    # Add this path
    path('login/', CustomLoginView.as_view(redirect_authenticated_user=True, template_name='users/login.html',
                                           authentication_form=LoginForm), name='login'),
    path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
]
```

- `redirect_authenticated_user=True` means that users who try to access the login page after they are authenticated will be redirected back.

- Templates aren't part of the resources the auth app gives us, so we need to provide a template both for the login and logout views. By default django looks for these template in *registration* directory. But we can override this default behavior and tell django to look for login and logout templates inside *users/templates/users/* directory. We can do this by passing in the `template_name` as an argument to `as_view` function.
- `authentication_form=LoginForm` - since we are using our extended login form.

After successful login, by default django redirects the user to a profile page. We can also modify this in our *settings.py* file, so let's open that up.

settings.py
```python
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = 'login'
```
- `LOGIN_REDIRECT_URL` tells django to redirect the user to the home page after a successful login.
- The `LOGIN_URL` is the URL or named URL pattern where requests are redirected for login when we are trying to limit access to certain pages. It defaults to '/accounts/login/'. But since we put our login route at `/login`, `LOGIN_URL` tells django where it can find this route.

That's it for part-I of login/logout system. In the next part we will create the templates and modify some stuffs. Stay tuned!

Thanks for your time, you can find the finished app in [github](https://github.com/earthcomfy/Django-registration-and-login-system). 

Feel free to ask, and any suggestions are welcome. See ya!