Search code examples
djangodjango-formsuser-registrationdjango-errors

Form Validation Errors Not Displayed in my HTML Template


I developed a login and registration system using Django on a single HTML page with a tabbing system. But, I encountered an error: upon registering, the page just refreshes. To troubleshoot, I debugged by printing errors to the console. It printed that the form is invalid. I intentionally provided invalid details to troubleshoot, like entering a password similar to the username or a password that isn't longer than 8 characters. It printed that in the console, but I want it to show the errors in the HTML template for each field. So, I wrote a login-register view. Everything seems to be okay in the view, but it still isn't showing the errors in the HTML template.

Forms

class CustomUserCreationForm(UserCreationForm):
    email = forms.EmailField(label="Email", max_length=255, required=True)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields[field_name]
            field.widget.attrs.update({'class': 'u-full-width bg-light pb-2', 'placeholder': field.label})
            
    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']

Views

def login_register_view(request):
    if request.user.is_authenticated:
        return redirect('core:home')

    if request.method == 'POST':
        action = request.POST.get('action')

        if action == 'login':
             # login functionality

        elif action == 'register':
            registration_form = CustomUserCreationForm(request.POST)
            if registration_form.is_valid():
                user = User.objects.create_user(
                    username=registration_form.cleaned_data['username'],
                    email=registration_form.cleaned_data['email'],
                    password=registration_form.cleaned_data['password1']
                )
                user.save()
                return redirect('core:login_register')

    login_form = CustomAuthenticationForm()
    registration_form = CustomUserCreationForm()
    context = {
        'login_form': login_form,
        'registration_form': registration_form,
    }

    return render(request, 'accounts/login_register.html', context)

HTML Template

<form method="post">
    {% csrf_token %}
    <div class="form-group">
        {{ registration_form.username.label_tag }}
        {{ registration_form.username }}
        {% if registration_form.username.errors %}
        <span class="error">{{ registration_form.username.errors }}</span>
        {% endif %}
    </div>

    <div class="form-group">
        {{ registration_form.email.label_tag }}
        {{ registration_form.email }}
        {% if registration_form.email.errors %}
        <span class="error">{{ registration_form.email.errors }}</span>
        {% endif %}
    </div>

    <div class="form-group">
        {{ registration_form.password1.label_tag }}
        {{ registration_form.password1 }}
        {% if registration_form.password1.errors %}
        <span class="error">{{ registration_form.password1.errors }}</span>
        {% endif %}
    </div>

    <div class="form-group">
        {{ registration_form.password2.label_tag }}
        {{ registration_form.password2 }}
        {% if registration_form.password2.errors %}
        <span class="error">{{ registration_form.password2.errors }}</span>
        {% endif %}
    </div>

    <button type="submit" name="action" value="register" class="btn btn-dark btn-full btn-medium">Register</button>
</form>

Solution

  • The problem is, that you reinitialize the form with registration_form = CustomUserCreationForm() in case it is not valid. Thus, removing also it's errors. Return the form with its POST data. E.g. something like this:

        ...
        elif action == 'register':
            registration_form = CustomUserCreationForm(request.POST)
            if registration_form.is_valid():
                user = User.objects.create_user(
                    username=registration_form.cleaned_data['username'],
                    email=registration_form.cleaned_data['email'],
                    password=registration_form.cleaned_data['password1']
                )
                user.save()
                return redirect('core:login_register')
            else:
                context = {
                    'registration_form': registration_form,
                }
                return render(request, 'accounts/login_register.html', context)  
        ...