Monday, January 21, 2019

Custom login and signup for multiple user in python

For making customize login in python , its a bit lengthy process and a bit difficult to understand but, i am trying to go straight forward towards the implementation and describe what exactly required ,
So, lets start the now:

lets start with surrounding  first: i am trying to create owner and staff for as multiple users , say owner can only create user and owner can be created by super users only , for such thing we need to have multiple logins access i.e login for owner and staff along with signup also,

now for this , lets create new app named account:

register the created app inside settings.py of the project

and inside urls.py  of the project :
path('account/', include('account.urls')),

now, inside urls.py of account app


from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from django.conf.urls.static import static
from .import views
urlpatterns = [
path('hotelowner/', views.HotelOwnerSignUpView.as_view(), name="hotelowner_signup"),
#path('hotelowner/', views.signup, name="hotelowner_signup"),
path('hotelstaff/', views.HotelStaffSignUpView.as_view(), name="hotelstaff_signup"),

]

Main important section is models.py of the account app  where we are going to overwrite Abstractclass of django default auth to add more fields on the form

from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
email=models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
is_hotel_staff=models.BooleanField(default=False)
is_hotel_owner=models.BooleanField(default=False)

form here we create our own user where all default feature of Abstract class is included like : username ,password, firstname etc. along with our customized field is_hotel_staff , is_hotel_owner

now , lets make forms.py  of the account app:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from account.models import User
from hotel.owner.models import HotelOwner
from hotel.staff.models import HotelStaff

class HotelOwnerSignUpForm(UserCreationForm):
email=forms.EmailField(required=True,label='Email')
first_name=forms.CharField(required=True,label='First Name')
last_name=forms.CharField(required=True,label='Last Name')
class Meta(UserCreationForm.Meta):
model=User
fields=("first_name","last_name","email","username","password1","password2")

@transaction.atomic
def save(self):
user=super().save(commit=False)
user.is_hotel_owner=True
user.save()
owner=HotelOwner.objects.create(user=user)
return user

class HotelStaffSignUpForm(UserCreationForm): class Meta(UserCreationForm.Meta): model=User fields=("first_name","last_name","email","username","password1","password2") # @transaction.atomic # def save(self): # user=super().save(commit=False) # user.is_hotel_staff=True # user.save() # staff=HotelStaff.objects.create(user=user) # return user


Here,

we store general information to the Users table and also store the user id just been created to the hotel owners table so that we can identify this one is the hotel ownera nd we can update extra information:
for more clearity lets see what is there in hotel owner model.py:

from account.models import User

class HotelOwner(models.Model):
name = models.CharField(max_length=80,null=True)
contact = models.BigIntegerField(null=True)
# email = models.EmailField(unique=True,null=True)
# password = models.CharField(max_length = 30,null=True)
image = models.ImageField(default='default.png')
address = models.CharField(max_length=80,null=True)
created_at = models.DateTimeField(default=datetime.now, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)


here,  we import user form account model, because now our default user is user created from accounts app, and also we make that user as primary key .

 also see the forms.py of owner for more clearity
from django import forms
from ..models import Hotels
from .models import HotelOwner

class HotelOwnerForm(forms.ModelForm):
class Meta:
model = HotelOwner
fields = ["name","contact","image","address","created_at"]

here, we haven't included user_id field in fields because we will not create input field for the user_id  we obtain that directly after username and password and other general information about the user is stored in account.users table previously.

Now its time to go deep towards views.py of account app, where there is major functioning

from django.shortcuts import render
from django.shortcuts import redirect
from django.views.generic import CreateView
from .forms import HotelOwnerSignUpForm
from .forms import HotelStaffSignUpForm
from django.http import HttpResponse
from account.models import User
from hotel.owner.models import HotelOwner

class HotelOwnerSignUpView(CreateView):
model = User
form_class = HotelOwnerSignUpForm
template_name = 'account/signup_form.html'


def form_valid(self, form):
user = form.save()
login(self.request, user)
user.save()
id=user.id
return redirect('hotel:ownerupdate',id)

class HotelStaffSignUpView(CreateView):
model = User
form_class = HotelStaffSignUpForm
template_name = 'account/signup_form.html'
# print(request.user)

def form_valid(self, form):
# user = form.save()
user=form.save(commit=False)
user.is_hotel_staff=True
user.save()
owner_id=self.request.user.id
staff=HotelStaff.objects.create(user=user,owner_id_id=owner_id)
id=user.id
return redirect('hotel:staffupdate',id)


after storing user in account_users table and storing user_id inside owners table, first the created user will be logged in to the system then will  redirect to the update function of the owner so that we can add general information to the owners profile or say update owners detail.

let me explain about namespace mathod used in the system:

return redirect('hotel:ownerupdate',id)

here hotel:ownerupdate refers to the updatefunction of the owner module which is included inside  hotel app ursl.py i.e.

# urls.py of hotel app

app_name='hotel'
urlpatterns = [
path('owner/', include('hotel.owner.urls')),
]

# urls.py of owner module of hotel app

path('update/<int:pk>', views.OwnerUpdate.as_view(), name="ownerupdate"),



now lets see the signup_forms.html inside of account app template:

{% extends 'travel/sign_base.html' %}
{% load crispy_forms_tags %}

{% block content %}
<div class="row">
<div class="col-md-8 col-sm-10 col-12">
<h2>Sign up as a {{ user_type }}</h2>
<form method="post" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ form|crispy }}
<button type="submit" class="btn btn-success">Sign up</button>
</form>
</div>
</div>
{% endblock %}

for using  'crispy_forms'

 install django-crispy-forms-1.7.2 in your environment and then include the in installed app thats all you need to do ,
and include crispy template pack also inside settings.py i.e:
CRISPY_TEMPLATE_PACK='bootstrap4'

since we are customizing everything so, lets make one small costumization for our easyness : i.e make out own login form, logout and our own redirect path after login , logout etc, for that just write following lines of codes inside settings.py

AUTH_USER_MODEL='account.User'
LOGIN_URL='login'
LOGOUT_URL='logout'
LOGIN_REDIRECT_URL='urltoredirect'
LOGOUT_REDIRECT_URL='login'


  • we set auth user model which was default user model of python to our user of account app 
  • login url to login which will understand  as login.html of registration template which will be override by our custom register template's login.html .
  • after logout we redirect to login.html again


Now, lets create registration folder inside templates folder of the project 

login.html 


{% extends 'travel/sign_base.html' %}

{% load crispy_forms_tags %}

{% block content %}
{% if form.non_field_errors %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
{% for error in form.non_field_errors %}
<p{% if forloop.last %} class="mb-0"{% endif %}>{{ error }}</p>
{% endfor %}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="row">
<div class="col-lg-4 col-md-6 col-sm-8 col-12">
<h2>Log in</h2>
<form method="post" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
{{ form.username|as_crispy_field }}
{{ form.password|as_crispy_field }}
<button type="submit" class="btn btn-primary">Log in</button>
</form>
</div>
</div>
{% endblock %}


For logout :
<a class="nav-link" href="{%url 'logout' %}"> Logout</a>

on clicking the logout button with above url  it will destroy the session and will be logged out automatically and redirect to the url that you have specified above.


Finally , you have come this way long and completed multple authentication  for multiple user

                                                    THANK YOU FOR SUPPORT AND TRUST :

If any problems occured while following this steps you cam comment below and get direct support form me













1 comment: