Building a Django Hotel Booking System - Part 1: Application Development
Learn how to build a Django-based hotel booking application with models, templates, and URL routing. Part 1 focuses on application architecture and development.
Building a Django Hotel Booking System - Part 1: Application Development
In this article series, I’ll walk you through a complete project I developed: Hotel Pegaso, a Django-based hotel booking system. This first part focuses on the application development, covering Django’s core features for building a robust web application.
📋 Project Overview
Hotel Pegaso is a comprehensive hotel booking application that demonstrates modern web development practices and Django’s powerful features.
What makes this project special? It combines Django’s robust framework with modern cloud practices, creating a production-ready application that handles real-world booking scenarios.
Core Features
The application showcases:
- Backend: Django framework with Python
- Database: PostgreSQL with Django ORM
- Architecture: MTV (Model-Template-View) pattern
- Features: Room management, booking system, user reviews
🔗 Source Code: You can find the complete source code on GitHub.
🛠️ Technology Stack
The application development uses the following technologies:
# Core Technologies
PYTHON_VERSION = "3.9"
FRAMEWORK = "Django"
DATABASE = "PostgreSQL"
EDITOR = "Visual Studio Code"
VERSION_CONTROL = "Git"
| Technology | Purpose | Why? |
|---|---|---|
| Visual Studio Code | Development environment | Powerful extensions for Python/Django |
| Git | Version control | Industry standard for collaboration |
| Python 3.9 | Programming language | Modern Python with type hints support |
| Django | Web framework | Batteries-included approach |
| PostgreSQL | Relational database | Production-ready, scalable database |
🚀 Why Django?
I chose Django for this project because it offers several advantages that made development faster and more reliable.
Django’s Philosophy: “Don’t repeat yourself” (DRY) and “batteries included” mean you spend more time building features and less time on boilerplate code.
1. Rapid Development
Django’s “batteries included” philosophy provides many built-in features out of the box:
# Built-in features available immediately
from django.contrib import admin # Admin interface
from django.contrib.auth import authenticate # User authentication
from django.core.mail import send_mail # Email functionality
from django.forms import ModelForm # Automatic forms
2. ORM Integration
Seamless database management without writing SQL queries manually:
# Instead of raw SQL like this:
# SELECT * FROM rooms WHERE available = TRUE AND price < 100
# You write elegant Python code:
available_rooms = Room.objects.filter(available=True, price__lt=100)
3. Admin Interface
Automatic admin panel for managing database objects - a huge time saver!
Pro Tip: The Django admin interface alone can save weeks of development time by providing instant CRUD operations for all your models.
4. Cloud Integration
Easy integration with cloud services like Microsoft Azure, AWS, and Google Cloud.
5. MTV Architecture
Clean separation of concerns (Model-Template-View) for maintainable code that scales.
🏗️ Application Architecture
Let’s dive into the core architectural components that make this application work.
Models and Database Design
The application uses Django’s ORM to define database models in models.py.
Understanding Django ORM: Think of it as a translator between your Python code and SQL database. You write Python, Django handles the database.
Example: Room Model
from django.db import models
class Room(models.Model):
"""Hotel room with pricing and availability"""
room_number = models.CharField(max_length=10, unique=True)
room_type = models.CharField(max_length=50)
price_per_night = models.DecimalField(max_digits=10, decimal_places=2)
capacity = models.IntegerField()
available = models.BooleanField(default=True)
description = models.TextField()
def __str__(self):
return f"Room {self.room_number} - {self.room_type}"
class Meta:
ordering = ['room_number']
Benefits of Django ORM
This approach allows us to:
Define schema using Python classes
- Type-safe and IDE-friendly
- No SQL syntax errors
- Version controlled with your code
Automatically generate migrations
# Create migration files
python manage.py makemigrations
# Output:
# Migrations for 'hotel':
# hotel/migrations/0001_initial.py
# - Create model Room
# - Create model Booking
# - Create model Review
Apply changes to the database
# Apply migrations to database
python manage.py migrate
# Output:
# Running migrations:
# Applying hotel.0001_initial... OK
Core Models
Our application includes three key models:
Room Model
- Hotel room details (number, type, description)
- Pricing information (price per night)
- Availability status (boolean flag)
- Capacity (number of guests)
Booking Model
- Guest reservations (guest name, contact)
- Check-in/check-out dates (datetime fields)
- Booking status (pending, confirmed, cancelled)
- Room reference (foreign key to Room)
Review Model
- Customer feedback (text review)
- Star ratings (1-5 stars)
- Review comments (detailed feedback)
- User and room references (foreign keys)
Template System
Django’s template engine (Jinja2) enables dynamic HTML generation with powerful features.
Templates = Separation of Concerns: Keep your HTML separate from Python logic. This makes your code cleaner and easier to maintain.
Template Inheritance Example
The project uses template inheritance to maintain consistency across pages:
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}Hotel Pegaso{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
{% include 'navbar.html' %}
<main>
{% block content %}
<!-- Page content goes here -->
{% endblock %}
</main>
{% include 'footer.html' %}
</body>
</html>
<!-- room_list.html -->
{% extends 'base.html' %}
{% block title %}Available Rooms - Hotel Pegaso{% endblock %}
{% block content %}
<h1>Available Rooms</h1>
{% for room in rooms %}
<div class="room-card">
<h2>{{ room.room_type }}</h2>
<p>Price: ${{ room.price_per_night }}/night</p>
</div>
{% endfor %}
{% endblock %}
Benefits
This approach allows reusable components like navigation bars and footers to be:
- Defined once - Write it once, use it everywhere
- Included across multiple pages - Consistent user experience
- Easily maintained and updated - Change in one place, updates everywhere
URL Routing
The urls.py file maps URLs to view functions, creating clean and intuitive URL patterns.
Clean URLs = Better SEO: Django’s URL routing makes it easy to create meaningful, SEO-friendly URLs without exposing implementation details.
URL Configuration Example
# urls.py
from django.urls import path
from . import views
urlpatterns = [
# List all available rooms
path('rooms/', views.room_list, name='room_list'),
# View specific room details
path('rooms/<int:room_id>/', views.room_detail, name='room_detail'),
# Create a new booking
path('booking/new/<int:room_id>/', views.create_booking, name='create_booking'),
# Edit existing booking
path('booking/<int:booking_id>/edit/',
views.edit_booking_view,
name='edit_booking_view'),
# Cancel booking
path('booking/<int:booking_id>/cancel/',
views.cancel_booking,
name='cancel_booking'),
]
Corresponding View Function
# views.py
from django.shortcuts import render, get_object_or_404
from .models import Room, Booking
def edit_booking_view(request, booking_id):
"""Edit an existing booking"""
booking = get_object_or_404(Booking, id=booking_id)
if request.method == 'POST':
# Handle form submission
booking.check_in_date = request.POST.get('check_in')
booking.check_out_date = request.POST.get('check_out')
booking.save()
return redirect('booking_detail', booking_id=booking.id)
return render(request, 'booking_form.html', {'booking': booking})
How It Works
Django extracts URL parameters through pattern matching and passes them as arguments to the corresponding view function, enabling dynamic page rendering.
Example URL: /booking/42/edit/
- Django matches the pattern
- Extracts
booking_id=42 - Calls
edit_booking_view(request, booking_id=42)
💡 Key Learnings
Building this application provided valuable insights into several Django features that every developer should know.
1. Django ORM
Lesson Learned: The ORM isn’t just about avoiding SQL - it’s about writing database-agnostic code that can easily switch between SQLite (development), PostgreSQL (production), or any other database.
Power of abstraction for database operations:
# Complex query made simple
expensive_available_rooms = Room.objects.filter(
available=True,
price_per_night__gte=200
).select_related('hotel').prefetch_related('amenities')
# Equivalent to a complex JOIN query in SQL
2. Template Inheritance
Reusable UI components improve code maintainability and consistency.
Before (without inheritance):
- Duplicate navigation code in every template
- Inconsistent styling across pages
- Nightmare to maintain
After (with inheritance):
- Single source of truth for layout
- Consistent user experience
- Easy to update site-wide changes
3. URL Routing
Clean and intuitive URL patterns make the application easy to navigate and understand.
# RESTful URL design
/rooms/ # List all rooms
/rooms/101/ # View room 101
/booking/new/101/ # Book room 101
/booking/42/edit/ # Edit booking 42
4. Admin Interface
Built-in administration capabilities save development time and provide instant CRUD functionality.
# admin.py - Just register your models
from django.contrib import admin
from .models import Room, Booking, Review
@admin.register(Room)
class RoomAdmin(admin.ModelAdmin):
list_display = ['room_number', 'room_type', 'price_per_night', 'available']
list_filter = ['available', 'room_type']
search_fields = ['room_number', 'description']
# That's it! Full admin interface is ready
⏭️ Coming Next: Cloud Deployment
In Part 2: Cloud Deployment on Azure of this series, I’ll show you how to deploy this Django application to the cloud using modern DevOps practices.
What You’ll Learn
- Infrastructure as Code with Terraform - Define your entire infrastructure in code
- Automated deployments with CI/CD pipelines - Push to deploy automatically
- Cloud hosting on Microsoft Azure - Leverage enterprise-grade cloud infrastructure
- Zero-touch deployment strategies - Deploy without manual intervention
- Production-ready security and scalability - Make it ready for real users
Sneak Peek: We’ll deploy this application to Azure App Service with PostgreSQL, set up automated CI/CD with GitHub Actions, and manage everything with Terraform!
👉 Continue to Part 2: Cloud Deployment on Azure
📚 Resources
Want to learn more? Check out these resources:
- Project Repository - Full source code with documentation
- Django Documentation - Official Django docs
- Django ORM Documentation - Deep dive into the ORM
- Django Templates - Template language reference
This is Part 1 of a two-part series on building and deploying a Django hotel booking system. The application demonstrates best practices in Django development that can be applied to any web project.