1

I am making an app which has login page. I am using default django username and password fields.I want to add some css to it.How can we modify the default style and make it look good

My HTML is of this form

<!DOCTYPE html>
{% load staticfiles %}
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Purple Admin</title>
  <link rel="stylesheet" href="{% static 'css/materialdesignicons.min.css' %}">
  <!-- plugins:css -->
  <link rel="stylesheet" href="{% static 'css/perfect-scrollbar.min.css' %}">
  <!-- endinject -->
  <!-- plugin css for this page -->
  <link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}">
  <!-- End plugin css for this page -->
  <!-- inject:css -->
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
  <!-- endinject -->
  <link rel="shortcut icon" href="{% static 'images/favicon.png' %}">
</head>

<body>
  <div class="container-scroller">
    <div class="container-fluid page-body-wrapper">
      <div class="row">
        <div class="content-wrapper full-page-wrapper d-flex align-items-center auth-pages">
          <div class="card col-lg-4 mx-auto">
            <div class="card-body px-5 py-5">
              <h3 class="card-title text-left mb-3">Login</h3>
              <form method="post" action="{% url 'login' %}">
                <div class="form-group">
                  <label>Username: </label>
                  {{ form.username }}
                </div>
                <div class="form-group">
                  <label>Password: </label>
                    {{ form.password }}
                </div>
                <div>
                 {% if form.errors %}
                    <font color="red">Your username and/or password didn't match. Please try again.</font>
                            {% endif %}
                </div>
                <div class="form-group d-flex align-items-center justify-content-between">
                  <a href="#" class="forgot-pass">Forgot password</a>
                </div>
                <div class="text-center">
                  <button type="submit" class="btn btn-primary btn-block enter-btn">Login</button>
                </div>
                <p class="sign-up">Don't have an Account?<a href="#"> Sign Up</a></p>
              </form>
            </div>
          </div>
        </div>
        <!-- content-wrapper ends -->
      </div>
      <!-- row ends -->
    </div>
    <!-- page-body-wrapper ends -->
  </div>
  <!-- container-scroller -->
  <!-- plugins:js -->
  <script src="{% static 'js/jquery.min.js' %}"></script>
  <script src="{% static 'js/popper.min.js' %}"></script>
  <script src="{% static 'js/bootstrap.min.css' %}"></script>
  <script src="{% static 'js/perfect-scrollbar.jquery.min.js' %}"></script>

  <!-- endinject -->
  <!-- inject:js -->
  <script src="{% static 'js/off-canvas.js' %}"></script>
  <script src="{% static 'js/misc.js' %}"></script>
  <!-- endinject -->
</body>

</html>

Variables {{ form.username }} and {{ form.password }} are having default styling to them.I just want to add a css class to them.How can I do that in this template itself

NewBie
  • 3,124
  • 2
  • 11
  • 19

2 Answers2

1

Lets say that you want to add a class or placeholder like:

<input type="text" class="SomeClass" placeholder="TypeSomething..."><input>

in your forms.py import your model and then:

class YourModelForm(forms.ModelForm):

    class Meta:
        model = YourModel
        #if you want to use all models then set field = to '__all__' (whithout the [] )
        fields = ['Username']

    username = forms.TextImput(
            widget=forms.TextInput(attrs={
                'class': 'SomeClass',
                'autofocus': True,
                'placeholder': 'TypeSomething'
                }
            )
    )

and finally in your views.py, import your form and add it to form_class :

Class YourLoginView(FormView):
    form_class = YourModelForm

I have this snipped if you want for the login/logout views (you need to import your own form and put it in form_class):

from django.utils.http import is_safe_url
from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login
from django.contrib.auth.views import LogoutView
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import FormView

class LoginView(FormView):
    """
    Provides the ability to login as a user with a username and password
    """
    template_name = 'login.html'
    success_url = '/'
    form_class = AuthenticationForm
    redirect_field_name = '/'

    @method_decorator(sensitive_post_parameters('password'))
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        # Sets a test cookie to make sure the user has cookies enabled
        request.session.set_test_cookie()

        return super(LoginView, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        auth_login(self.request, form.get_user())

        # If the test cookie worked, go ahead and
        # delete it since its no longer needed
        if self.request.session.test_cookie_worked():
            self.request.session.delete_test_cookie()

        return super(LoginView, self).form_valid(form)

    def get_success_url(self):
        redirect_to = self.request.GET.get(self.redirect_field_name)
        if not is_safe_url(url=redirect_to, host=self.request.get_host()):
            redirect_to = self.success_url
        return redirect_to


class Logout(LogoutView):
    """
    Provides users the ability to logout
    """
    template_name = 'logout.html'

And for the AuthenticationForm:

import unicodedata

from django import forms
from django.contrib.auth import (
    authenticate, get_user_model, password_validation,
)
from django.utils.translation import gettext, gettext_lazy as _
from django.utils.text import capfirst

UserModel = get_user_model()


class UsernameField(forms.CharField):
    def to_python(self, value):
        return unicodedata.normalize('NFKC', super().to_python(value))


class AuthenticationForm(forms.Form):
    """
    (This is a modified version of the original:
    django.contrib.auth.forms.AuthenticationForm)

    Base class for authenticating users. Extend this to get a form that accepts
    username/password logins.
    """
    username = UsernameField(
        label=_("Username"),
        max_length=32,
        widget=forms.TextInput(attrs={
            'autofocus': True,
            'placeholder': _('Type your username')
            }
        ),
    )
    password = forms.CharField(
        label=_("Password"),
        strip=False,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': _('Contraseña')
        }
        ),
    )

    error_messages = {
        'invalid_login': _(
            "Please enter a correct %(username)s and password. Note that both "
            "fields may be case-sensitive."
        ),
        'inactive': _("This account is inactive."),
    }

    def __init__(self, request=None, *args, **kwargs):
        """
        The 'request' parameter is set for custom auth use by subclasses.
        The form data comes in via the standard 'data' kwarg.
        """
        self.request = request
        self.user_cache = None
        super().__init__(*args, **kwargs)

        # Set the label for the "username" field.
        self.username_field = UserModel._meta.get_field(
            UserModel.USERNAME_FIELD)
        if self.fields['username'].label is None:
            self.fields['username'].label = capfirst(
                self.username_field.verbose_name)

    def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if username is not None and password:
            self.user_cache = authenticate(
                self.request, username=username, password=password)
            if self.user_cache is None:
                # An authentication backend may reject inactive users. Check
                # if the user exists and is inactive, and raise the 'inactive'
                # error if so.
                try:
                    self.user_cache = UserModel._default_manager.get_by_natural_key(
                    username)
                except UserModel.DoesNotExist:
                    pass
                else:
                    self.confirm_login_allowed(self.user_cache)
                raise forms.ValidationError(
                    self.error_messages['invalid_login'],
                    code='invalid_login',
                    params={'username': self.username_field.verbose_name},
                )
            else:
                self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data

    def confirm_login_allowed(self, user):
        """
        Controls whether the given User may log in. This is a policy setting,
        independent of end-user authentication. This default behavior is to
        allow login by active users, and reject login by inactive users.

        If the given user cannot log in, this method should raise a
        ``forms.ValidationError``.

        If the given user may log in, this method should return None.
        """
        if not user.is_active:
            raise forms.ValidationError(
                self.error_messages['inactive'],
                code='inactive',
            )

    def get_user_id(self):
        if self.user_cache:
            return self.user_cache.id
        return None

    def get_user(self):
        return self.user_cache
Loki
  • 70
  • 1
  • 11
  • As far as my understanding goes what I can do is I will write the form in form.py.Then in urls.py declare login url and write a view for it.This view will then call a template to which the form will be passed – NewBie Mar 14 '18 at 19:00
  • forms.py is used to customize the fields behavior and how they will be displayed. In the urls.py you will declare your LoginView like this: `path('accounts/login/',a.LoginView.as_view(), name='Login')` and don't forget to declare your login redirect `LOGIN_REDIRECT_URL = "accounts/login/"` (same as the one you declare in your urls.py). And finally yes, the view will call a template to which the form will be passed. – Loki Mar 14 '18 at 19:04
0

You could set the class attribute in the form widget of each field (see the django docs).

I ended up using django-bootstrap4 and there are other similar packages you can find through google.

Other options were discussed in this post for example.

Ralf
  • 16,086
  • 4
  • 44
  • 68
  • 1
    I dont have anything in my forms.py to set attribute for – NewBie Mar 14 '18 at 17:30
  • 1
    So I need to set the attribute in template only – NewBie Mar 14 '18 at 17:30
  • Were do you get the `form` instance from that is being used in the template? Do you create it or are you using a generic view or something else? – Ralf Mar 14 '18 at 17:33
  • I used a very simple/generic login page which is default in django – NewBie Mar 14 '18 at 17:34
  • I got it from here [Mozilla developer network](https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication) – NewBie Mar 14 '18 at 17:35
  • Ah, using [djangos class-based authentication views](https://docs.djangoproject.com/en/2.0/topics/auth/default/#module-django.contrib.auth.views). In that case the easiest way I know is to just write the HTML form yourself. – Ralf Mar 14 '18 at 17:48
  • The harder option is to subclass djangos `LoginView` to add classes to your form and replace it in your `urls.py` file. – Ralf Mar 14 '18 at 17:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/166837/discussion-between-newbie-and-ralf). – NewBie Mar 14 '18 at 17:49