'In Django, how can we stop losing the details filled in the form, if it fails validation?

I am using the UserCreationForm for user registration in my Django web app. When the user fills in the detail (username, password, confirm_password) and submits, then if the form fails validation (maybe because username already exists or password don't match or password is too short) then the user is redirected back to the register page.

Now my problem is that when he is redirected back to the register page, the form is blank again, i.e. he has to start all over again, which is not a good user experience because his form might fail one or more times.

I want that if the form fails validation and when he is redirected to the registration form, he should see his previously filled in details so that he can just correct the field which is causing the error and move on. Is there any way the data can be retained?

Here is my code of the register function in views.py:

def register(request):
    if request.method == 'POST':
        
        form = UserCreationForm(request.POST or None)
        if form.is_valid():
            # some code
            return redirect('login')

        else:
            messages.error(request, form.errors)
            return HttpResponseRedirect(reverse("register"))

    else:
        return render(request, 'accounts/register.html')

my register.html:

<form method="POST" action="{% url 'register' %}">
    {% csrf_token %}
    <input name="username" type="text" class="..." style="...">
    <input name="password1" type="password" class="..." style="...">
    <input name="password2" type="password" class="..." style="...">
    <button type="submit">Sign up</button>
</form>

Edit: I have not passed the form in context to the template, so that I can control the CSS of my input fields, which I am not sure how to do otherwise without creating forms.py file separately.

If it's not possible to retain details in the form, then what should I do to at least improve the present situation?



Solution 1:[1]

Instead of return redirect just render the response with the form object again:

def register(request):
    if request.method == 'POST':
        
        form = UserCreationForm(request.POST or None)
        if form.is_valid():
            # some code
            return redirect('login')
        messages.error(request, form.errors)

    else:
        form = UserCreationForm()
    return render(request, 'accounts/register.html', {'form': form})

In the template since you want to control css use django-widget-tweaks:

{% load widget_tweaks %}

<form method="POST" action="{% url 'register' %}">
    {% csrf_token %}
    {% render_field form.username class="..." style="..." %}
    {% render_field form.password1 class="..." style="..." %}
    {% render_field form.password2 class="..." style="..." %}
    <button type="submit">Sign up</button>
</form>

The load widget tweaks must be at the top of the html file like all load tags.

Solution 2:[2]

def register(request):
    context = {}
    if request.method == 'POST':
        
        form = UserCreationForm(request.POST or None)
        if form.is_valid():
            # some code
            return redirect('login')
        else:
           context['form'] = form
           messages.error(request, form.errors)

    context['form'] = UserCreationForm()
    return render(request, 'accounts/register.html', context)

it should work

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ledorub