Search code examples
htmldjangoformsdjango-forms

How to convert html form to Django form and preserve styling?


I have a pure html form which I wish to use to collect sign-in information using a Django backend.

Here is my pure non-Django html form:

<form id="contactForm" method="POST">
    <div class="row">
        <div class="form-group">
            <div class="col-md-12">
                <label>Username or E-mail Address</label>
                <input type="text" value="" class="form-control">
            </div>
        </div>
    </div>
    <div class="row">
        <div class="form-group">
            <div class="col-md-12">
                <a class="pull-right" href="#">(Lost Password?)</a>
                <label>Password</label>
                <input type="password" value="" class="form-control">
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-md-6">
            <span class="remember-box checkbox">
                <label for="rememberme">
                    <input type="checkbox" id="rememberme" name="rememberme">Remember Me
                </label>
            </span>
        </div>
        <div class="col-md-6">
            <a href="#" class="btn btn-primary btn-orange uppercase pull-right">Login</a>
        </div>
    </div>
</form>

Here is what it looks like with all the styling:

enter image description here

In order to process this form I have created a view:

def login_page(request):
    form = LoginForm(request.POST or None)
    context = {'form': form}

    next_ = request.GET.get('next')
    next_post = request.POST.get('next')
    redirect_path = next_ or next_post or None

    if form.is_valid():
        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password')
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            try:
                del request.session['guest_email_id']
            except:
                pass
            if is_safe_url(redirect_path, request.get_host()):
                return redirect(redirect_path)
            return redirect('/')
        else:
            print('Error')

    return render(request, 'users/login.html', context)

I am aware that I need a form.py class which I have created and is as follows:

class LoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput())

How do I use this form class to render the same form as done by the html preserving the styling. Additionally, once rendered how do I submit the form data for processing to the view by using the link disguised as a button below?

<a href="#" class="btn btn-primary btn-orange uppercase pull-right">Login</a>

Solution

  • In my experience with Django, it is not possible to create an HTML form as is in a Form inheriting from forms.ModelForm or forms.Form. The best we can do is, assign classes to the widgets which are assigned to the specific form fields in form of attrs, like so:

    class LoginForm(forms.Form):
        username = forms.CharField()
        password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    

    This will attach your CSS classes to the rendered form when you use {{ form.as_p }} or similar others in your template.

    Then for rendering the divs, you unpack the form yourself, rather than letting Django do the work, like so:

    <form id="contactForm" method="POST">
        <div class="row">
            <div class="form-group">
                <div class="col-md-12">
                    {{ form.username.errors }}
                    <label for="{{form.username.id_for_label}}">Username or E-mail Address</label>
                    {{ form.username }}
                </div>
            </div>
        </div>
        <div class="row">
            <div class="form-group">
                <div class="col-md-12">
                    {{form.password.errors}}
                    <a class="pull-right" href="#">(Lost Password?)</a>
                    <label for="{{form.password.id_for_label}}">Password</label>
                    {{form.password}}
                </div>
            </div>
        </div>
    .........
    

    And so on.

    However, it is generally considered a bad practice to couple your design and logic, which we clearly are doing here.

    References: Django Documentation - Working With Forms