Sdev
Sdev

Reputation: 81

Customize Form with Django FORM API

I am currently creating an register/login form with the Django framework, since I am new to this framework, I don't know much about the FORM API.

I am not using the FORM API, since I don't know if I can customize it. Is there any way to use my styling with the FORM API? As the state of now, I am just creating my own one, without using the API, but since the FORM API is more secure and much faster to set up for user creation, I would like to use it.

So my question is, can I implement custom styling with the FORM API? Including <input>,<div> etc..

Here is my HTML form:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

    <div class="limiter">
        <div class="container-login100" style="background:black;">
            <div class="wrap-login100">
                <form class="login100-form validate-form"  method='POST' action="{% url 'users:register' %}" >
                    {% csrf_token %}
                    <span class="login100-form-logo">
                        <i class="zmdi zmdi-landscape"></i>
                    </span>
                    <span class="login100-form-title p-b-34 p-t-27">
                        Register
                    </span>
                    <div class="wrap-input100 validate-input" data-validate = "Enter username">
                        <input class="input100" type="text" name="username" placeholder="Username" required>
                        <span class="focus-input100" data-placeholder="&#xf207;"></span>
                    </div>
                    <div class="wrap-input100 validate-input" data-validate="Enter password">
                        <input class="input100" type="password" name="pass" placeholder="Password" required>
                        <span class="focus-input100" data-placeholder="&#xf191;"></span>
                    </div>
    
                    <div class="wrap-input100 validate-input" data-validate="Confirm password">
                        <input class="input100" type="password" name="pass-confirm" placeholder="Confirm Password" required>
                        <span class="focus-input100" data-placeholder="&#xf191;"></span>
                    </div>
    
                    <div class="wrap-input100 validate-input" data-validate="Enter Email">
                        <input class="input100" type="email" name="mail" placeholder="E-Mail" required>
                        <span class="focus-input100" data-placeholder="&#xf191;"></span>
                    </div>
    
                    <div class="container-login100-form-btn">
                        <button class="login100-form-btn" type="submit" name="submit" value="submit">
                            Register
                        </button>
                    </div>
    
                    <div class="text-center p-t-90">
                        <a class="txt1" href="login">
                            Already registered?
                        </a>
                    </div>
    
                </form>
            </div>
        </div>
    </div>

Here is my views.py backend:

def register(request):
    if request.method == "POST":
        username = request.POST["username"]
        password = request.POST["pass"]
        password_confirm = request.POST["pass-confirm"]
        email = request.POST["mail"]
        submit = request.POST["submit"]
        
        
        print("UserName : ", username)
        print('Email : ', email)
        print('Password : ', password)
        print('Password Confirm : ', password_confirm)
        
        SpecialSym =['$', '@', '#', '%', '?']
        confirm = False
        
        if request.POST.get("submit"):
            if len(username) < 7:
                
                print('Username must be more than 10 char.')
                confirm = False
                messages.error(request, "Username must be more than 10 char.", 'red')
                return HttpResponseRedirect(reverse('users:register'))
            
            if len(username) > 15:
          
                print('Username must be less than 15 char.')
                confirm = False
                messages.error(request, "Username must be less than 15 char.", 'red')
                return HttpResponseRedirect(reverse('users:register'))
            
            if any(char in SpecialSym for char in username):
                print('Username can\'t contain special characters.')
                confirm = False
                messages.error(request, "Username can't contain special characters", 'red')
                return HttpResponseRedirect(reverse('users:register'))
            
            if len(password) < 8:
                print("Your password is too short")
                confirm = False
                messages.error(request, "Your password is too short.", 'red')
                return HttpResponseRedirect(reverse('users:register'))
            
            if len(password) > 25:
                print("Your password must be less than 25 char")
                confirm = False
                messages.error(request, "Your password must be less than 25 char.", 'red')
                return HttpResponseRedirect(reverse('users:register')) 
            
            if not any(char.isdigit() for char in password):
                print('Password should have at least one numeral')
                confirm = False
                messages.error(request, "Your password should have at least one numeral ", 'red')
                return HttpResponseRedirect(reverse('users:register'))

            if not any(char.isupper() for char in password):
                print('Password should have at least one uppercase letter')
                confirm = False
                messages.error(request, "Your password should have at least one uppercase letter ", 'red')
                return HttpResponseRedirect(reverse('users:register'))
                
            if not any(char.islower() for char in password):
                print('Password should have at least one lowercase letter')
                confirm = False
                messages.error(request, "Your password should have at least one lowercase letter ", 'red')
                return HttpResponseRedirect(reverse('users:register'))
                        
            if not any(char in SpecialSym for char in password):
                print('Password should have at least one of the symbols $@#?')
                confirm = False
                messages.error(request, "Your password should have at least one of these symbols: $@#? ", 'red')
                return HttpResponseRedirect(reverse('users:register'))
            
            if (password != password_confirm):
                print("Passwords don't match")
                confirm = False
                messages.error(request, "Passwords don't match.", 'red')
                return HttpResponseRedirect(reverse('users:register'))
                
            if confirm == True:
                
                messages.success(request, "Success! form submitted.", 'green')
                return HttpResponseRedirect(reverse('users:register'))
                
                
    return render(request, 'users/register.html')

Upvotes: 0

Views: 580

Answers (1)

Sunderam Dubey
Sunderam Dubey

Reputation: 8837

You can use in-built UserCreationForm[django-doc], which is at the path from django.contrib.auth.forms import UserCreationForm.

Now, as your current code, you don't need to use messages framework, as the in-built Form has already many validations, you have done.

In your code you can implement in following way, simply do this:

I am providing only a minimal reproducible example,as you have many css classes in the templates so I only add my_class to every field, you can add your own class, you can see it with Ctrl+U or page source.

urls.py

from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [
    path('', views.register, name='home'),
    path('success/', views.success, name='success')
]

views.py

from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib.auth.hashers import make_password
from django.urls import reverse

from home.forms import MyUserCreationForm


def register(request):
    if request.method == 'POST':
        form = MyUserCreationForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password1 = form.cleaned_data['password1']
            email = form.cleaned_data['email']
            user_data = User(username=username,
                             password=make_password(password1), email=email)

            user_data.save()
            return HttpResponseRedirect(reverse('users:success'))
    else:
        form = MyUserCreationForm()
    return render(request, 'users/register.html', {'form': form})


def success(request):
    return render(request, 'users/thanks.html')

forms.py

from django.contrib.auth.forms import UserCreationForm
from django import forms
from django.contrib.auth import password_validation

from django.utils.translation import gettext, gettext_lazy as _
from django.contrib.auth.models import User


class MyUserCreationForm(UserCreationForm):
    password1 = forms.CharField(
        label=_("Password"),
        strip=False,
        widget=forms.PasswordInput(
            attrs={'autocomplete': 'new-password', 'class': 'my_class', 'placeholder': 'password'}),
        help_text=password_validation.password_validators_help_text_html(),
        error_messages={'required': 'password is required'}
    )
    password2 = forms.CharField(
        label=_("Password confirmation"),
        widget=forms.PasswordInput(
            attrs={'autocomplete': 'new-password', 'class': 'my_class', 'placeholder': 'confirm password'}),
        strip=False,
        help_text=_("Enter the same password as before, for verification."),
        error_messages={'required': 'password confirm is required'}
    )
    email = forms.CharField(widget=forms.EmailInput(
        attrs={'class': 'my_class', 'placeholder': 'Email'}), error_messages={'required': 'Email is required'})

    class Meta:
        model = User
        fields = ['username', 'email']
        error_messages = {
            'username': {'required': 'Username is required'},
        }
        widgets = {
            'username': forms.TextInput(attrs={'class': 'myclass', 'placeholder': 'Username'}),
        }

Note: you can use any class in any field, you can change here for every field attrs={'class': 'my_class'), I have used my_class in every field just for example, you can view it in page source.

Note: The example might be a bit complex, since I have inherited and changed the django's inbuilt form for adding css classes.

register.html or template file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .red{
            color:red;
            font-size:1.15rem;
        }
    </style>
</head>
<body>
    {% if form %}
    <form method="POST" novalidate>
        {% csrf_token %}
        {% if form.non_field_errors %}
        {% for error in form.non_field_errors %}
        <div class="red">
            <p>{{error}}</p>
        </div>
        {% endfor %}
        {% endif %}

        {% for field in form %}
        <div>
            {{field.label_tag}} {{field}}
            <br>
            {% for error in field.errors  %}
                <div class="red">
                    <span>{{error}}</span>
                </div>
            {% endfor %}
        </div>
        {% endfor %}
        <input type="submit" value="Save">
    </form>
    {% else %}
    <p>There is some error, form does not come from view.</p>
    {% endif %}
</body>
</html>

thanks.html (which will be used for redirection after successfully submitting the form)

<body>
    <h2>You are now a user! logged in !</h2>
</body>

Through this example, your data successfully saved in the database, you can see it by creating superuser, through python manage.py createsuperuser and by logged in into the admin site, in the Users table.

The above work can become more easy with class based authentication views[django-doc].

Upvotes: 1

Related Questions