Django
Django Image Processing Webapp Part V

Django Image Processing Webapp Part V

Implementing User Signup and Login.

Creating a Signup Form

Create an app named accounts.

#terminal
python manage.py startapp accounts

Add the new app to INSTALLED_APPS in /image_project/settings.py

..................................
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'Image',
    'crispy_forms',
    'crispy_bootstrap4',
    'accounts',
]
.............................................

Create following function in /accounts/views.py with the following code.

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm

# Create your views here.
def signupaccount(request):
    return render(request,'signupaccount.html',{'form':UserCreationForm})

Create /accounts/urls.py and put path related to signupaccount.

from django.urls import path
from . import views

urlpatterns = [
    path('signupaccount/',views.signupaccount,name='signupaccount'),
]

Now, add following code in image_project/urls.py.

....................................
urlpatterns = [
    path('admin/', admin.site.urls),
    path("",include("Image.urls")),
    path('accounts/',include('accounts.urls')),

]
......................................

Now, create /accounts/templates/signupaccount.html.

{% extends 'base.html' %}
{% block content %}
<div class="card mb-3">
    <div class="row g-0">
        <div>
            <div class="card-body">
                <h5 class="card-title">Sign Up</h5>
                <p class="card-text">
                    <form method="post">
                        {% csrf_token %}
                        {{form.as_p}}
                        <button type="submit" class="btn btn-primary">
                            Sign Up
                        </button>
                    </form>
                </p>


            </div>
        </div>
    </div>
</div>
{% endblock content %}

Run the server, and visit http://127.0.0.1:8000/accounts/signupaccount/

Fill the form and click Sign Up button

For now our application does nothing on submission.

Creating a user

Add the following line of codes in /accounts/views.py.

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm

from django.contrib.auth.models import User
from django.contrib.auth import login
from django.shortcuts import redirect

# Create your views here.
def signupaccount(request):
    if request.method == 'GET':
        return render(request,'signupaccount.html',{'form':UserCreationForm})
    
    else:
        if request.POST['password1'] == request.POST['password2']:
            user = User.objects.create_user(request.POST['username'],
                                            password=request.POST['password'])
            user.save()
            login(request,user)
            return redirect('imageHome')

Run the server, and visit http://127.0.0.1:8000/accounts/signupaccount/ again.

Now, visit http://127.0.0.1:8000/admin/

Sign in with superuser account.

Click on users:

Handling User creation Errors

Checking whether passwords do not match

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm

from django.contrib.auth.models import User
from django.contrib.auth import login
from django.shortcuts import redirect

# Create your views here.
def signupaccount(request):
    if request.method == 'GET':
        return render(request,'signupaccount.html',{'form':UserCreationForm})
    
    else:
        if request.POST['password1'] == request.POST['password2']:
            user = User.objects.create_user(request.POST['username'],
                                            password=request.POST['password1'])
            user.save()
            login(request,user)
            return redirect('imageHome')

        else:
            return render(request,'signupaccount.html',{'form':UserCreationForm,'error':'Passwords do not match'})

Now add following code in /accounts/templates/signupaccount.html.

{% extends 'base.html' %}
{% block content %}
<div class="card mb-3">
    <div class="row g-0">
        <div>
            <div class="card-body">
                <h5 class="card-title">Sign Up</h5>
                {% if error %}
                    <div class="alert alert-danger mt-3" role="alert">
                        {{ error }}
                    </div>

                {% endif %}
                <p class="card-text">
                    <form method="post">
                        {% csrf_token %}
                        {{form.as_p}}
                        <button type="submit" class="btn btn-primary">
                            Sign Up
                        </button>
                    </form>
                </p>


            </div>
        </div>
    </div>
</div>
{% endblock content %}

Run the server, and visit http://127.0.0.1:8000/accounts/signupaccount/ again.

Enter different passwords.

Checking if a username already exists

Again, edit /accounts/views.py

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm

from django.contrib.auth.models import User
from django.contrib.auth import login
from django.shortcuts import redirect

from django.db import IntegrityError

# Create your views here.
def signupaccount(request):
    if request.method == 'GET':
        return render(request,'signupaccount.html',{'form':UserCreationForm})
    
    else:
        if request.POST['password1'] == request.POST['password2']:
            try:
                user = User.objects.create_user(request.POST['username'],
                                            password=request.POST['password1'])
            
                user.save()
                login(request,user)
                return redirect('imageHome')
            except IntegrityError:
                return render(request,'signupaccount.html',{'form':UserCreationForm,
                                                            'error':'Username already taken. Choose new username.'})

        else:
            return render(request,'signupaccount.html',{'form':UserCreationForm,'error':'Passwords do not match'})

Run the server, and visit http://127.0.0.1:8000/accounts/signupaccount/ again. Try to signup with username that already exists.

Customizing UserCreationForm

Create a new file /accounts/forms.py

from typing import Any
from django.contrib.auth.forms import UserCreationForm

class UserCreateForm(UserCreationForm):
    def __init__(self, *args: Any, **kwargs):
        super(UserCreateForm,self).__init__(*args,**kwargs)

        for fieldname in ['username','password1','password2']:
            self.fields[fieldname].help_text = None
            self.fields[fieldname].widget.attrs.update(
                {'class':'form-control'}
            )

Now, edit /accounts/views.py to create the form with our UserCreateForm

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm



from django.contrib.auth.models import User
from django.contrib.auth import login
from django.shortcuts import redirect

from django.db import IntegrityError

from .forms import UserCreateForm

# Create your views here.
def signupaccount(request):
    if request.method == 'GET':
        return render(request,'signupaccount.html',{'form':UserCreateForm})
    
    else:
        if request.POST['password1'] == request.POST['password2']:
            try:
                user = User.objects.create_user(request.POST['username'],
                                            password=request.POST['password1'])
            
                user.save()
                login(request,user)
                return redirect('imageHome')
            except IntegrityError:
                return render(request,'signupaccount.html',{'form':UserCreateForm,
                                                            'error':'Username already taken. Choose new username.'})

        else:
            return render(request,'signupaccount.html',{'form':UserCreateForm,'error':'Passwords do not match'})

Run the server, and visit http://127.0.0.1:8000/accounts/signupaccount/ again. And create another user.

Showing whether a user in logged in

Edit base.html as follow.

...................................................................
            <div class="collapse navbar-collapse" 
            id="navbarNavAltMarkup">
            <div class="navbar-nav ms=auto">
               
                
                <a class="nav-link" href="{% url 'imageform' %}">Upload Image</a>

            </div>
            <div class="navbar-nav ms=auto">
                {% if user.is_authenticated %}
                    <a class="nav-link" href="#">
                        Logout {{user.username}}
                    </a>
                {% else %}
                    <a class="nav-link" href="#">Login</a>
                    <a class="nav-link" href="#">Sign Up</a>

                {% endif %}

            </div>
        </div>
            </div>
        </nav>
        <div class="container">
            {% block content %}

            {% endblock content %}
        </div>
        .................................................

Visit http://127.0.0.1:8000/

Goto to http://127.0.0.1:8000/admin login and then visit http://127.0.0.1:8000/

Implementing Logout functionality

Add the following function in accounts/views.py.

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm



from django.contrib.auth.models import User
from django.contrib.auth import login,logout
from django.shortcuts import redirect

from django.db import IntegrityError

from .forms import UserCreateForm

# Create your views here.
def signupaccount(request):
    if request.method == 'GET':
        return render(request,'signupaccount.html',{'form':UserCreateForm})
    
    else:
        if request.POST['password1'] == request.POST['password2']:
            try:
                user = User.objects.create_user(request.POST['username'],
                                            password=request.POST['password1'])
            
                user.save()
                login(request,user)
                return redirect('imageHome')
            except IntegrityError:
                return render(request,'signupaccount.html',{'form':UserCreateForm,
                                                            'error':'Username already taken. Choose new username.'})

        else:
            return render(request,'signupaccount.html',{'form':UserCreateForm,'error':'Passwords do not match'})
        
#view for logout
def logoutaccount(request):
    logout(request)
    return redirect('imageHome')

Add the path to accounts/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('signupaccount/',views.signupaccount,name='signupaccount'),
    path('logout/',views.logoutaccount,name='logoutaccount'),
    
]

Edit base.html so that the links for Signup and logout can appear in navbar.

................................................................
            <div class="collapse navbar-collapse" 
            id="navbarNavAltMarkup">
            <div class="navbar-nav ms=auto">
               
                
                <a class="nav-link" href="{% url 'imageform' %}">Upload Image</a>

            </div>
            <div class="navbar-nav ms=auto">
                {% if user.is_authenticated %}
                    <a class="nav-link" href="{% url 'logoutaccount'%}">
                        Logout {{user.username}}
                    </a>
                {% else %}
                    <a class="nav-link" href="#">Login</a>
                    <a class="nav-link" href="{% url 'signupaccount'%}">Sign Up</a>

                {% endif %}

            </div>
        </div>
            </div>
        </nav>
        <div class="container">
            {% block content %}

            {% endblock content %}
        </div>
       ..................................................

Implementing the login functionality

Edit the accounts/views.py to implement the login.

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm



from django.contrib.auth.models import User
from django.contrib.auth import login,logout,authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import redirect

from django.db import IntegrityError

from .forms import UserCreateForm

.....................................................................
#view for login
def loginaccount(request):
    if request.method == 'GET':
        return render(request,'loginaccount.html',{'form':AuthenticationForm})
    else:
        user = authenticate(request,username=request.POST['username'],
                            password=request.POST['password'])
        if user is None:
            return render(request,'loginaccount.html',{'form':AuthenticationForm(),'error':'username and password do not match'})
        
        else:
            login(request,user)
            return redirect('imageHome')

Add the path in accounts/urls.py.

from django.urls import path
from . import views

urlpatterns = [
    path('signupaccount/',views.signupaccount,name='signupaccount'),
    path('logout/',views.logoutaccount,name='logoutaccount'),
    path('login/',views.loginaccount,name='loginaccount'),
]

Create accounts/templates/loginaccount.html

{% extends 'base.html' %}
{% block content %}
<div class="card mb-3">
    <div class="row g-0">
        <div>
            <div class="card-body">
                <h5 class="card-title">Login</h5>
                {% if error %}
                <div class="alert alert-danger mt-3" role="alert">
                    {{ error }}

                </div>
                {% endif %}
                <p class="card-text">
                    <form method="post">
                        {% csrf_token %}
                        {{ form.as_p }}
                        <button type="submit" class="btn btn-primary">
                            Login
                        </button>
                    </form>
                </p>
            </div>
        </div>
    </div>
</div>

Now edit base.html to add the login to navigation bar.

........................................................................
            <div class="collapse navbar-collapse" 
            id="navbarNavAltMarkup">
            <div class="navbar-nav ms=auto">
               
                
                <a class="nav-link" href="{% url 'imageform' %}">Upload Image</a>

            </div>
            <div class="navbar-nav ms=auto">
                {% if user.is_authenticated %}
                    <a class="nav-link" href="{% url 'logoutaccount'%}">
                        Logout {{user.username}}
                    </a>
                {% else %}
                    <a class="nav-link" href="{% url 'loginaccount' %}">Login</a>
                    <a class="nav-link" href="{% url 'signupaccount'%}">Sign Up</a>

                {% endif %}

            </div>
        </div>
            </div>
        </nav>
        <div class="container">
            {% block content %}

            {% endblock content %}
        </div>
   ..........................................................

Output So Far

Sigiup

After signup, user is logged in and directed to home page.

After clicking logout user will be redirected to home page. Check how the options in navigation bar changes.

Now, login

For loggedin users only

The logout functionality should be only used when user is logged in.

Edit accounts/views.py as follow.

from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
.............................................................
from django.contrib.auth.decorators import login_required

.............................................................
        
#view for logout
@login_required
def logoutaccount(request):
    
    logout(request)
    return redirect('imageHome')

............................................................

We also want to provide the facility of processing the image to logged in user.

Edit Image/views.py as follow.

from django.shortcuts import render
from django.http import HttpResponse
from django.core.paginator import Paginator,PageNotAnInteger, EmptyPage
from django.contrib.auth.decorators import login_required

...........................................................
@login_required    
def imageForm(request):
    if request.method == 'POST':
        form = ImageForm(request.POST,request.FILES)
        if form.is_valid():
            #save the model instance
            instance = form.save(commit=False)

            instance.grayscale()
            instance.save()
            #latest_object = ImageEnhance.objects.latest('id')
            #latest_object.grayscale()

            return render(request,"image_process.html",{"form":form,'object':instance,"filter":"Not Processed"})
        else:
            latest_object = ImageEnhance.objects.latest('id')
            process = request.POST["first-dropdown"]
            try:
                sub_process = request.POST["second-dropdown"]
                
            except:
                pass

            try:
                tuning_value = request.POST["num-Input"]
            except:
                pass
.....................................................................

We only want the image upload option to appear only when the user to logged in.

Edit base.html

.....................................................................
              
            
           
            
            <div class="navbar-nav ms=auto">
                {% if user.is_authenticated %}
                
               
                
                    <a class="nav-link" href="{% url 'imageform' %}">Upload Image</a>
    
               
                    <a class="nav-link" href="{% url 'logoutaccount'%}">
                        Logout ({{user.username}})
                    </a>
                {% else %}
                    <a class="nav-link" href="{% url 'loginaccount' %}">Login</a>
                    <a class="nav-link" href="{% url 'signupaccount'%}">Sign Up</a>

                {% endif %}

..............................................................

Output

Run the server and visit http://127.0.0.1:8000/

For now we do not see option to upload the image.

Login with your username and password.

After login you can see the options to upload image and logout.

Upload the image, process it as you like.