Hotel Management Project
Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
Advantages of using django
- Django provides a default admin panel
- Django comes with couple of cool libraries that will make work easier for developer.
- It improves search engine optimization
- Django has strong security
- Django comes with a roburst admin panel which is customizable
- Django has great Object relational Mapper
- Highly Scalable
- Helps developers build applications faster
- Django comes fully loaded with tools needed to accomplish app developement tasks like Authentication, site maps, RSS feeds etc.
- Can be used to develop any type of application
Requirements
- Visit this link to install python 3 if you don't have it installed in your machine
- Download VScode here if you wish to use it for this project
- Click here to download git bash
Follows the instructions below and code along or code the code snippets to your IDE
I used VScode to build this project. You may want to use vscode or your preferred IDE, you shiould get the same result irrespective
Create a vitual Environment
We will be using Python's package manager pip to install this and other packages like Django which we will require later on. First, let's get virtualenv installed.
pip install virtualenv
Once that is done, create a folder called projects anywhere you like (I created mine in the documents folder) then cd into it.
mkdir hotel_system
cd hotel_system
Once inside the projects folder, create another folder called hms. This folder will hold our app.
mkdir hms
At this point, we need to create the environment to hold our requirements. We will do this inside the hms folder.
virtualenv hotelenv
Now we need to actvate our virtual environment
Install Django
pip install django
The above code snippets will install django into the virtual environment created in our project folder
pip install psycopg2_binary
This package is the postgres engine that will enable us use postgres database in our project
Create project and apps
After you’ve successfully installed Django, you’re ready to create the scaffolding for your new web application. A Django project is a high-level unit of organization that contains logic that governs your whole web application. Each project can contain multiple apps while Django app is a lower-level unit of your web application. You can have zero to many apps in a project, and you’ll usually have at least one app. You’ll learn more about apps in the next section.
django-admin startproject name
Here our project name is hotel_system. You may choose to replace name with your preferred project name. Now let's create an Authentication app. Remember to use your name of choice for the app name
python manage.py startapp name
Git Setup
Follow the steps below to set up git and workflows for this project
- Create and checkout to a new git branch called (use any name of your choice). And in this branch
- Create a .github folder. In this folder
- Create PULL_REQUEST_TEMPLATE.md file and add PR format of your choice.
- Create a workflow folder and add ci.yml file and implement configuration for continuous integration
- Make a commit for your changes in the setup_ci branch and push the branch to your repository
- Visit the repository on Github and create a pull request from the branch and merge it to master or main branch
- Go back to GIT and checkout to master and pull the merged changes into your local master.
- So you start the cycle again for each part of the tutorial and name each branch the topic treated in the part.
Create a .env file inside the project folder and configure your database settings as shown below.
SECRET_KEY=django-insecure-63yz=-tc&x51kjvazxle%=32mmu8!t7h(a*bq#u0!rx1xw!m%u
DATABASE_NAME=hoteldb
DATABASE_USER=postgres
DATABASE_PASS=PASSWORD
DATABASE_PORT=5432
DATABASE_HOST=localhost
Hotel-system/hotelsystem/manage.py
/Users/decagon/Documents/hotelproject/Hotel-system/hotelsystem/manage.py
Create a .gitignore file and add .env file in your .gitignore file
Got setings.py inside the project folder and include our apps in the list of install apps. Befoe this, follow the steps above on how to create python app and create three more apps namely: 'booking', 'Receptionist' and 'customer'. Bravo! Now follow the snippet below.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'authentication',
'booking',
'Receptionist',
'customer',
'rest_framework',
]
Database setup
Follow these steps to configure your your postgresql database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': env('DATABASE_NAME'),
'USER' : env('DATABASE_USER'),
'PASSWORD' : env('DATABASE_PASS'),
'PORT' : env('DATABASE_PORT'),
'HOST' : env('DATABASE_HOST')
}
}
Let us configure our template folder. The folder tells django where to look for templates ie html files for your apps. In the code below, we update the 'DIR' field with the path to out templates folder.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Let us configure static and media directories
STATIC_URL = '/static/'
STATIC_ROOT=os.path.join(BASE_DIR,'static')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Now let us create our models for these apps and make migrations
Authentication app models
from django.db import models
from PIL import Image
class Customer(models.Model):
username=models.CharField(max_length=100)
password=models.CharField(max_length=100)
email=models.CharField(max_length=50)
profile_pic=models.ImageField(upload_to="media", height_field=None,
width_field=None, max_length=None,blank=True)
phone_no=models.CharField(max_length=50)
address=models.TextField()
state=models.CharField(max_length=30,blank=True)
pin_code=models.IntegerField(blank=True)
def __str__(self):
return "Customer: "+self.username
class RoomManager(models.Model):
username=models.CharField(max_length=100)
password=models.CharField(max_length=100)
email=models.CharField(max_length=50)
profile_pic=models.ImageField(upload_to="media", height_field=None,
width_field=None, max_length=None,blank=True)
phone_no=models.CharField(max_length=50)
gender=models.CharField(max_length=20)
def __str__(self):
return "Room Manager: "+self.username
Open the admin.py file and register the models as shown below
from django.contrib import admin
from authentication.models import Customer, RoomManager
admin.site.register(Customer)
admin.site.register(RoomManager)
Paste the code below in the views.py file of the Authentication app
from django.shortcuts import render,redirect
from .models import Customer,RoomManager
from django.contrib.auth.hashers import make_password,check_password
from django.contrib import messages
#mesages.info(request,'mail taken')
def user_login(request):
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='manager':
return redirect('manager_dashboard')
if request.method=="POST":
username=request.POST['username']
password=request.POST['password']
if not len(username):
messages.warning(request,"Username field is empty")
redirect('user_login')
elif not len(password):
messages.warning(request,"Password field is empty")
redirect('user_login')
else:
pass
if Customer.objects.filter(username=username):
user=Customer.objects.filter(username=username)[0]
password_hash=user.password
res=check_password(password,password_hash)
if res==1:
request.session['username'] = username
request.session['type'] = 'customer'
return render(request,'booking/index.html',{})
else:
messages.warning(request,"Username or password is incorrect")
redirect('user_login')
else:
messages.warning(request,"No, Account exist for the given Username")
redirect('user_login')
else:
redirect('user_login')
return render(request,'login/user_login.html',{})
def manager_login(request):
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='manager':
return redirect('manager_dashboard')
if request.method=="POST":
username=request.POST['username']
password=request.POST['password']
if not len(username):
messages.warning(request,"Username field is empty")
redirect('manager_login')
elif not len(password):
messages.warning(request,"Password field is empty")
redirect('manager_login')
else:
pass
if RoomManager.objects.filter(username=username):
user=RoomManager.objects.filter(username=username)[0]
password_hash=user.password
res=check_password(password,password_hash)
if res==1:
request.session['username'] = username
request.session['type'] = 'manager'
return render(request,'booking/index.html',{})
else:
messages.warning(request,"Username or password is incorrect")
redirect('manager_login')
else:
messages.warning(request,"No, Account exist for the given Username")
redirect('manager_login')
else:
redirect('manager_login')
return render(request,'login/manager_login.html',{})
def user_signup(request):
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='manager':
return redirect('manager_dashboard')
if request.method=="POST":
username=request.POST['username']
email=request.POST['email']
if Customer.objects.filter(username=username) or Customer.objects.filter(email=email):
messages.warning(request,"Account already exist, please Login to continue")
else:
password=request.POST['password']
address=request.POST['address']
pin_code=request.POST['pin_code']
profile_pic=request.FILES.get('profile_pic',None)
phone_no=request.POST['phone_no']
state=request.POST['state']
error=[]
if(len(username)<3): error.append(1)
messages.warning(request,"Username Field must be greater than 3 character.")
if(len(password)<5):
error.append(1)
messages.warning(request,"Password Field must be greater than 5 character.")
if(len(email)==0):
error.append(1)
messages.warning(request,"Email field can't be empty")
if(len(phone_no)!=10):
error.append(1)
messages.warning(request,"Valid Phone number is a 10 digit-integer.")
if(len(error)==0):
password_hash = make_password(password)
customer=Customer(username=username,password=password_hash,email=email,phone_no=phone_no,
address=address,state=state,pin_code=pin_code,profile_pic=profile_pic)
customer.save()
messages.info(request,"Account Created Successfully, please Login to continue")
redirect('user_signup')
else:
redirect('user_signup')
else:
redirect('user_signup')
return render(request,'login/user_login.html',{})
def manager_signup(request):
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='manager':
return redirect('manager_dashboard')
if request.method=="POST":
username=request.POST['username']
email=request.POST['email']
if RoomManager.objects.filter(username=username) or RoomManager.objects.filter(email=email):
messages.warning(request,"Account already exist, please Login to continue")
else:
password=request.POST['password']
profile_pic=request.FILES.get('profile_pic',None)
phone_no=request.POST['phone_no']
error=[]
if(len(username)<3):
error.append(1)
messages.warning(request,"Username Field must be greater than 3 character.")
if(len(password)<5):
error.append(1)
messages.warning(request,"Password Field must be greater than 5 character.")
if(len(email)==0):
error.append(1)
messages.warning(request,"Email field can't be empty")
if(len(phone_no)!=10):
error.append(1)
messages.warning(request,"Valid Phone number is a 10 digit-integer.")
if(len(error)==0):
password_hash = make_password(password)
r_manager=RoomManager(username=username,password=password_hash,email=email,
phone_no=phone_no,profile_pic=profile_pic)
r_manager.save()
messages.info(request,"Account Created Successfully, Please login to continue")
redirect('manager_signup')
else:
redirect('manager_signup')
else:
redirect('user_signup')
return render(request,'login/manager_login.html',{})
def logout(request):
if request.session.get('username', None):
del request.session['username']
del request.session['type']
return render(request,"login/logout.html",{})
else:
return render(request,"login/user_login.html",{})
Now go to the urls.py of the Authenication app and follow the lines below to configure the urls route
from django.urls import path,include
from . import views
urlpatterns=[
path('login',views.user_login,name='user_login'),
path('login1',views.manager_login,name='manager_login'),
path('signup',views.user_signup,name='user_signup'),
path('signup1',views.manager_signup,name='manager_signup'),
path('dashboard/',include('customer.urls')),
path('dashboard1/',include('Receptionist.urls')),
path('add-room/',include('Receptionist.urls'))
]
from django.urls import path,include
from . import views
urlpatterns=[
path('login',views.user_login,name='user_login'),
path('login1',views.manager_login,name='manager_login'),
path('signup',views.user_signup,name='user_signup'),
path('signup1',views.manager_signup,name='manager_signup'),
path('dashboard/',include('customer.urls')),
path('dashboard1/',include('Receptionist.urls')),
path('add-room/',include('Receptionist.urls'))
]
click to download the Authentication app login, logout and manager_login templates
booking app models
from django.db import models
from authentication.models import Customer,RoomManager
from datetime import date
class Contact(models.Model):
name=models.CharField(max_length=100)
email=models.CharField(max_length=100)
message=models.TextField(max_length=2000)
def __str__(self):
return self.name
class Rooms(models.Model):
manager=models.ForeignKey(RoomManager, on_delete=models.CASCADE)
room_no=models.CharField(max_length=5, )
room_type=models.CharField(max_length=50)
is_available=models.BooleanField(default=True)
price=models.FloatField(default=1000.00)
no_of_days_advance=models.IntegerField()
start_date=models.DateField(auto_now=False, auto_now_add=False)
room_image=models.ImageField(upload_to="media", height_field=None, width_field=None, max_length=None,default='0.jpeg')
def __str__(self):
return "Room No: "+str(self.id)
'''
class RoomImage(models.Model):
room=models.ForeignKey(Rooms, on_delete=models.CASCADE)
room_image=models.ImageField(upload_to="media", height_field=None, width_field=None, max_length=None)
'''
class Booking(models.Model):
room_no=models.ForeignKey(Rooms, on_delete=models.CASCADE)
user_id=models.ForeignKey(Customer, on_delete=models.CASCADE)
start_day=models.DateField(auto_now=False, auto_now_add=False)
end_day=models.DateField(auto_now=False, auto_now_add=False)
amount=models.FloatField()
booked_on=models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return "Booking ID: "+str(self.id)
@property
def is_past_due(self):
return date.today()>self.end_day
Views of the booking app
Below are the functions the describe the views of the booking app which we are gonna render in our template
from django.shortcuts import render,redirect
from .models import Contact
from .models import Rooms,Booking
from authentication.models import Customer
from django.contrib import messages
from django.http import HttpResponse
import datetime
def index(request):
return render(request,'booking/index.html',{})
def contact(request):
if request.method=="GET":
return render(request,"contact/contact.html",{})
else:
username=request.POST['name']
email=request.POST['email']
message=request.POST['message']
data=Contact(name=username,email=email,message=message)
data.save()
return render(request,"contact/contact.html",{'message':'Thank you for contacting us.'})
def book(request):
if request.method=="POST":
start_date=request.POST['start_date']
end_date=request.POST['end_date']
request.session['start_date']=start_date
request.session['end_date']=end_date
start_date=datetime.datetime.strptime(start_date, "%d/%b/%Y").date()
end_date=datetime.datetime.strptime(end_date, "%d/%b/%Y").date()
no_of_days=(end_date-start_date).days
data=Rooms.objects.filter(is_available=True,no_of_days_advance__gte=no_of_days,start_date__lte=start_date)
request.session['no_of_days']=no_of_days
return render(request,'booking/book.html',{'data':data})
else:
return redirect('index')
def book_now(request,id):
if request.session.get("username",None) and request.session.get("type",None)=='customer':
if request.session.get("no_of_days",1):
no_of_days=request.session['no_of_days']
start_date=request.session['start_date']
end_date=request.session['end_date']
request.session['room_no']=id
data=Rooms.objects.get(room_no=id)
bill=data.price*int(no_of_days)
request.session['bill']=bill
roomManager=data.manager.username
return render(request,"booking/book-now.html",{"no_of_days":no_of_days,"room_no":id,"data":data,"bill":bill,
"roomManager":roomManager,"start":start_date,"end":end_date})
else:
return redirect("index")
else:
next="book-now/"+id
return redirect('user_login')
def book_confirm(request):
room_no=request.session['room_no']
start_date=request.session['start_date']
end_date=request.session['end_date']
username=request.session['username']
user_id=Customer.objects.get(username=username)
room=Rooms.objects.get(room_no=room_no)
amount=request.session['bill']
start_date=datetime.datetime.strptime(start_date, "%d/%b/%Y").date()
end_date=datetime.datetime.strptime(end_date, "%d/%b/%Y").date()
data=Booking(room_no=room,start_day=start_date,end_day=end_date,amount=amount,user_id=user_id)
data.save()
room.is_available=False
room.save()
del request.session['start_date']
del request.session['end_date']
del request.session['bill']
del request.session['room_no']
messages.info(request,"Room has been successfully booked")
return redirect('user_dashboard')
def cancel_room(request,id):
data=Booking.objects.get(id=id)
room=data.room_no
room.is_available=True
room.save()
data.delete()
return HttpResponse("Booking Cancelled Successfully")
def delete_room(request,id):
data=Rooms.objects.get(id=id)
manager=data.manager.username
if manager==request.session['username']:
data.delete()
return HttpResponse("You have deleted the room successfully")
else:
return HttpResponse("Invalid Request")
URLs mapping of the booking app
Follow the code below to map the urls to each views function we created.
from django.urls import path
from . import views
urlpatterns=[
path('',views.index,name='index'),
path('book',views.book,name='book'),
path('contact-us',views.contact,name='contact-us'),
path('book-now/',views.book_now,name='book-now'),
path('cancel-room/',views.cancel_room,name='cancel-room'),
path('delete-room/',views.delete_room,name='delete-room'),
path('confirm-now-booking',views.book_confirm,name="book_confirm")
]
click to download the templates and static files for the booking app
Customer app views
Below are the code snippets for the customer view for our project
from django.shortcuts import render,redirect
from authentication.models import Customer
from booking.models import Booking
import datetime
def dashboard(request):
if request.session.get('username',None) and request.session.get('type',None)=='manager':
return redirect('manager_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='customer':
username=request.session['username']
data=Customer.objects.get(username=username)
booking_data=Booking.objects.filter(user_id=data).order_by('-id')
counts=booking_data.filter(end_day__lt=datetime.datetime.now()).count()
available=len(booking_data)-counts
return render(request,"user_dash/index.html",{"data":booking_data,"count":counts,"available":available})
else:
return redirect("user_login")
def details(request,id,booking_id):
if not request.session.get('username',None):
return redirect('manager_login')
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
try:
booking_data=Booking.objects.get(id=booking_id)
user=Customer.objects.get(id=id)
return render(request,"user_dash/details.html",{"user":user,"booking_data":booking_data})
except:
return redirect("/manager/dashboard1/")
URLs mapping of the customer views
from django.urls import path
from . import views
urlpatterns=[
path('',views.dashboard,name='user_dashboard'),
path('details//',views.details,name='user_details')
]
click to download the Customer app templates and static files
Creating the receptionist app views
from django.shortcuts import render,redirect
from authentication.models import RoomManager
from booking.models import Booking,Rooms
from datetime import date
from django.contrib import messages
import datetime
def dashboard(request):
if not request.session.get('username',None):
return redirect('manager_login')
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.session.get('username',None) and request.session.get('type',None)=='manager':
username=request.session['username']
data=RoomManager.objects.get(username=username)
room_data=data.rooms_set.all()
booked=room_data.filter(is_available=False).count()
print(booked)
return render(request,"manager_dash/index.html",{"room_data":room_data,"manager":data,"booked":booked})
else:
return redirect("manager_login")
def add_room(request):
if not request.session.get('username',None):
return redirect('manager_login')
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
if request.method=="GET":
return render(request,"manager_dash/add-room.html",{})
else:
room_no=request.POST['room_no']
room_type=request.POST['room_type']
price=request.POST['price']
room_image=request.FILES.get('room_image',None)
no_of_days_advance=request.POST['no_of_days_advance']
start_day=request.POST['start_day']
error=[]
if(len(room_no)<1): error.append(1)
messages.warning(request,"Room No Field must be atleast 3 digit like 100.")
if(len(room_type)<5):
error.append(1)
messages.warning(request,"Select a valid Room Type.")
if(len(price)<=2):
error.append(1)
messages.warning(request,"Please enter price")
if(len(no_of_days_advance)<1):
error.append(1)
messages.warning(request,"Please add valid no of days a user can book room in advance.")
if(len(start_day)<3):
error.append(1)
messages.warning(request,"Please add the starting day")
if(not len(error)):
manager=request.session['username']
manager=RoomManager.objects.get(username=manager)
room=Rooms(room_no=room_no,room_type=room_type,price=price,no_of_days_advance=no_of_days_advance,
start_date=datetime.datetime.strptime(start_day, "%d %B, %Y").date(),room_image=room_image,manager=manager)
room.save()
messages.info(request,"Room Added Successfully")
return redirect('/manager/dashboard1/')
else:
return redirect('/user/add-room/new/')
def update_room(request,room_no):
if not request.session.get('username',None):
return redirect('manager_login')
if request.session.get('username',None) and request.session.get('type',None)=='customer':
return redirect('user_dashboard')
room=Rooms.objects.get(room_no=room_no)
if request.method=="GET":
return render(request,"manager_dash/edit-room.html",{"room":room})
else:
price=request.POST['price']
no_of_days_advance=request.POST['no_of_days_advance']
error=[]
if(len(price)<=2):
error.append(1)
messages.warning(request,"Please enter correct price")
if(len(no_of_days_advance)<1):
error.append(1)
messages.warning(request,"Please add valid no of days a user can book room in advance.")
if(not len(error)):
manager=request.session['username']
manager=RoomManager.objects.get(username=manager)
room.price=price
room.no_of_days_advance=no_of_days_advance
room.save()
messages.info(request,"Room Data Updated Successfully")
return redirect('/manager/dashboard1/')
else:
return redirect('/user/add-room/update/'+room.room_no,{"room":room})
MApping the receptionest app urls
from django.urls import path
from . import views
urlpatterns = [
path('',views.dashboard,name="manager_dashboard"),
path('new/',views.add_room,name="add_room"),
path('update//',views.update_room,name="update_room"),
]
click to download the Receptionist app templates and static files
Configure the project urls.py file
We need to go to the project folder and open the urls.py module to route the urls of our apps. Follow the snippe below to do this
"""room_slot URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from django.conf import settings
from django.conf.urls.static import static
from authentication import views
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('booking.urls')),
path('user/',include('authentication.urls')),
path('manager/',include('authentication.urls')),
path('logout',views.logout,name='logout'),
path('api/',include('api.urls'))
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Deploy project to Heroku
We will use Heroku to deploy this project. To do this you'll need an account with Heroku and a few configurations. Please visit this to learn about how to deploy django app to heroku and follow the steps outlined there.