2

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>
Tom Finet
  • 2,056
  • 6
  • 30
  • 54
  • Possible duplicate of [CSS styling in Django forms](https://stackoverflow.com/questions/5827590/css-styling-in-django-forms) – saketk21 Aug 07 '18 at 20:09

3 Answers3

1

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

saketk21
  • 435
  • 4
  • 13
  • Thanks for the answer! Just one question, how do I set the id for the label used in the for attribute of the label tag? – Tom Finet Aug 08 '18 at 07:24
  • In my experience, I don't think you can. I double-checked the documentation to be sure, and it was mentioned nowehere. If that was a priority, then in the view, I'd access the `request.POST` dict and instantiate a new `LoginForm` on my own, and then use it for validation. – saketk21 Aug 08 '18 at 23:35
  • However, I don't think that is necessary unless absolutely critical - If you need it in JS, then instead of separating JS code into files, write a `{% block js %}...{% endblock %}` in your `base.html` and while writing contents of this block, use `{{ form.field.id_for_label }}` as you would normally. – saketk21 Aug 08 '18 at 23:40
0

If you are using the POST method, you are required to use {% csrf_token %} else while rendering it is bound to throw an error.

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
0

Your pure non-django form looks a lot like Bootstrap formatting. If that's all there is to it, then you can save yourself a lot of time by using django-crispy-forms with one of its Bootstrap template packs

Even if there's more to it, django-crispy-forms is much more amenable to custom formatting than raw Django is.

nigel222
  • 7,582
  • 1
  • 14
  • 22