Creating The Sign Up Page Part I
Tags: python, django, webdev, codenewbie
Published: 2021-08-25 10:03:13

Hello, glad to see you here again. In today's part of the series, we are going to create the sign up page.

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

Okay to create users we need a model right, we need to define what kind of attributes users should have. Django comes with a built in User model whose primary attributes are:
* username
* password
* email
* first_name
* last_name


If we want our users to have more attributes than this built in model gives us, there are a couple of ways to do that and we will see one way in the future when we create a user profile. But for now we are using the Django User model as it is so we should be fine.

Next, we need a form that will be displayed to the users, validate the data and save it to the database. Luckily we don't have to reinvent the wheel because Django has a built in easy to use UserCreationForm. 

> UserCreationForm is a form that creates a user, with no privileges, from the given username and password. - [docs](https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/forms/)

- Looks good, but what if we want to include extra fields in our form and get other information about the user upon sign up? 

For that, we can just simply extend the built in model form and add more fields. I'm going to add email, firstname, and lastname of the user.

**Don't forget that the fields am adding are already in the User model**


Create forms.py module inside the users app and first let's import the necessary dependencies.

forms.py
```python
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
```
- Forms in Django is a class whose fields map to HTML form elements. 
- forms class has different fields for handling different types of data. For example, CharField, DateField... Check out the [docs](https://docs.djangoproject.com/en/3.2/ref/forms/fields/#built-in-field-classes) here to look at more of these fields. 
- These form fields are represented to the user as an HTML widget (Widgets render HTML form elements) therefore unless we explicitly specify the widget for our form field, Django will use default widgets which may not look that good.
- By overriding the default widget for the form field, we can bootstrapify our form fields.

forms.py
```python
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

class RegisterForm(UserCreationForm):
    # fields we want to include and customize in our form
    first_name = forms.CharField(max_length=100,
                                 required=True,
                                 widget=forms.TextInput(attrs={'placeholder': 'First Name',
                                                               'class': 'form-control',
                                                               }))
    last_name = forms.CharField(max_length=100,
                                required=True,
                                widget=forms.TextInput(attrs={'placeholder': 'Last Name',
                                                              'class': 'form-control',
                                                              }))
    username = forms.CharField(max_length=100,
                               required=True,
                               widget=forms.TextInput(attrs={'placeholder': 'Username',
                                                             'class': 'form-control',
                                                             }))
    email = forms.EmailField(required=True,
                             widget=forms.TextInput(attrs={'placeholder': 'Email',
                                                           'class': 'form-control',
                                                           }))
    password1 = forms.CharField(max_length=50,
                                required=True,
                                widget=forms.PasswordInput(attrs={'placeholder': 'Password',
                                                                  'class': 'form-control',
                                                                  'data-toggle': 'password',
                                                                  'id': 'password',
                                                                  }))
    password2 = forms.CharField(max_length=50,
                                required=True,
                                widget=forms.PasswordInput(attrs={'placeholder': 'Confirm Password',
                                                                  'class': 'form-control',
                                                                  'data-toggle': 'password',
                                                                  'id': 'password',
                                                                  }))

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'username', 'email', 'password1', 'password2']
```

- I added an id for the password fields because we are gonna use a plugin that shows password hide/show icon - you know that weird looking eye icon. But more on that later when we create the template.
- Under Meta class we can create the link between our model's fields and the different fields we want to have in our form(order matters).

Alright! Let's head over to *views.py* and use the form we just created.

Here I'm using class-based view to handle the register form. Check the [docs](https://docs.djangoproject.com/en/3.2/topics/class-based-views/intro/) for more info about what am using.

views.py
```python
from django.shortcuts import render, redirect 
from django.contrib import messages
from django.views import View

from .forms import RegisterForm


class RegisterView(View):
    form_class = RegisterForm
    initial = {'key': 'value'}
    template_name = 'users/register.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)

        if form.is_valid():
            form.save()

            username = form.cleaned_data.get('username')
            messages.success(request, f'Account created for {username}')

            return redirect(to='/')

        return render(request, self.template_name, {'form': form})
```

- First by overriding the `form_class` attribute, we are able to tell django which form to use, `template_name` -> the template we want django to look for
- If the request is get, it creates a new instance of an empty form.
- If the request is post, 
-- It creates a new instance of the form with the post data. Then checks if the form is valid or not by calling the [`form.is_valid()`](https://docs.djangoproject.com/en/3.2/ref/forms/api/) method.
-- Then if the form is valid, process the cleaned form data and save the user to our database.
- To let the user know that his/her account is successfully created, we can generate a flash message and display his/her username to the page they are getting redirected to(home page).

Next let's map our urlpatterns to our register view.

users/urls.py
```python
from django.urls import path
from .views import home, RegisterView  # Import the view here

urlpatterns = [
    path('', home, name='users-home'),
    path('register/', RegisterView.as_view(), name='users-register'),  # This is what we added
]
```

This is getting kinda long so, we will create the template in the next part.

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!