A full-stack Django hotel booking application showcasing responsive web design, secure user authentication, CRUD operations, database management, and deployment best practices.
Deployed Site: [The Capstone Hotel]
I have designed an accessible, user-friendly, and responsive front-end that meets accessibility guidelines and follows UX/UI design principles using HTML5, CSS3, Bootstrap 5, and JavaScript.
- Mobile-First Approach: Implemented Bootstrap grid system for responsiveness across different screen sizes
- Accessibility Features:
- Semantic HTML tags
- Correct heading hierarchy
- ARIA labels on form inputs
- Colour contrast meeting WCAG 2.1 AA standards
- Create an account, log in, and log out securely using Django-Allauth
- View available hotel rooms with detailed information and images
- Make bookings by selecting check-in date and number of nights
- Manage bookings (edit check-in date/nights, or cancel)
- Complete a contact form to contact the hotel with any questions
- HTML5: Semantic markup for structure
- CSS3: Page design
- Bootstrap 5: Pre-built components for consistency and responsiveness
- JavaScript: Minimal JavaScript provided by Django and third-party packages such as admin functionality, with primary logic handled server-side.
- Cloudinary: Image hosting and delivery
- Django-Summernote: Rich text editor for admin content
- Crispy Forms: Enhanced form rendering with Bootstrap integration
I have configured a secure Django web framework with a connected PostgreSQL database and custom models for the application. I designed an Entity Relationship Diagram (ERD) early in the project to organise my database architecture.
- Room Model: Stores hotel room types with descriptions, subtitles, and featured images
- RoomBooking Model: Manages user bookings with ForeignKey relationships to User and Room models
- AboutUs Model: Content management for the About page with rich text description and image
- ContactRequest Model: Stores contact form submissions from visitors
- User Model: Built-in Django authentication model with role-based access control
- On_delete=models.CASCADE: Ensures data integrity when related records are deleted
- User Isolation:
user=request.userfilter prevents users from viewing/editing other users' bookings - Data Validation:
MinValueValidator(1)prevents invalid no_of_nights values; clean() method validates past date attempts
I have used Agile tools to plan and track project tasks and progress. Documentation of user stories can be found here: Capstone Project User Stories
User stories were written early in the project and regularly reviewed using a Kanban board to track progress. Each user story was prioritised using Must-Have, Should-Have and Could-Have categories to ensure core functionality was delivered first. This approach helped keep the project focused and achievable within the given timeframe.
- Apps Structure: Separated concerns with
bookingapp for reservations andaboutapp for content management. - Model Validation: Implemented
clean()andsave()methods for data integrity - DRY Principle: Reusable templates (base.html), shared CSS utilities, model inheritance
- Documentation: Docstrings on models explaining purpose and relationships
- Naming Conventions: Clear, descriptive names for variables, functions, and classes (e.g.,
check_in,no_of_nights,RoomBooking)
Class-based views were used where appropriate to improve readability and maintainability, and view logic includes clear conditional handling for create, update and delete actions.
I have included wireframes and ERD driagram.
I missed AboutUs model from the initial ERD:
title = models.CharField(max_length=200)
description = TextField()
image = ImageField
The ERD was otherwise unchanged. I did decide to add enhancements such as @property decorator to the RoomBooking model. This was to add a status to the booking (past booking, check in today or upcoming) for clarity.
I added MinValueValidator(1) as automated tests failed on nunber of nights: 0.
I have maintained an organised database schema with clearly defined tables, relationships, and implemented migrations.
- Normalised Design: Data organised to minimise redundancy while maintaining relationships
- PrimaryKey/ForeignKey Relationships: User ← RoomBooking → Room (many-to-many through RoomBooking)
- Migration Management: Django migrations track all schema changes incrementally (0001_initial.py, 0002_room_featured_image.py, etc.)
python manage.py makemigrations # Create migration files python manage.py migrate # Apply migrations to database
Full CRUD functionality is implemented and tested with logged-in users able to:
- Create Booking: POST request with room_id, check_in_date, number_of_nights
- Automatic User Assignment: user=request.user ensures booking attributed to logged-in user
- View Rooms: RoomList view displays all available rooms (Room.objects.all())
- View Bookings: BookingList view shows only user's bookings (RoomBooking.objects.filter(user=request.user))
- Sorted Display: Bookings ordered by check_in then created_at for chronological clarity
- Status Property: Dynamic status property shows booking status (Past/Today/Confirmed)
- Edit Booking: Users can update check_in_date and no_of_nights through manage-booking.html form
- Validation: clean() method prevents backdating check-in dates
- Cancel Booking: POST action="delete" removes booking with user verification
- Success Messages: Django messages framework confirms deletion to user
I have added clear and concise notification messages that inform users of data changes and alerts on amendments and cancelations to ensure they do not make changes by accident. Confirmation dialogs prevent accidental deletions or amendments.
Forms are implemented using Django’s ModelForm system to ensure secure and consistent data handling.
- Required fields are enforced on all booking and contact forms
- Date validation: Users cannot select check-in dates in the past
- Numeric validation:
MinValueValidator(1)prevents invalid night values - Ownership checks: Bookings can only be edited or deleted by the user who created them
- Error handling: Invalid submissions are redirected with clear feedback to the user.
Users can securely register as a user, additionl admin level not accessible to registered users. Registered User can create bookings, view/edit/delete own bookings, submit contact forms. Admin User have full database access, content management (rooms, about page), view all bookings and contact requests. Unregistered users Can view rooms and about page, they can make a contact request, but cannot book (redirect to login).
Users can see logout button when logged in. I added a small message to the navbar so that users could see which account they are logged into when they are logged in. Links to manage bookings only appear when logged in.
Admin content is restricted with error messages or redirects for unauthorised access attempts. No user can see, edit, or delete another user's bookings with protection in views.py (user=request.user) and new bookings are automatically assigned to the current user
Automated tests were written using Django’s built-in testing framework to verify core functionality.
- Form validation tests (e.g. preventing invalid number of nights)
- Model tests to ensure correct behaviour of custom properties
- View tests to confirm correct redirects and access control
Python code was also checked using a PEP8 linter: https://pep8ci.herokuapp.com/ as seen here:
Not Applicable. This project uses Django server-side rendering with minimal custom JavaScript.
Manual testing was carried out across all key user flows:
- Account registration and login
- CRUD Booking functionality
- Access control for unauthorised users
- Contact form submission
- Responsive behaviour across mobile, tablet and desktop
No issues identified during testing. In addition, I invited family and friends to complete BETA testing and the site functioned correctly for everyone with positive feedback received.
The lower score for Best Practices was due to the embedded map HTTPS security policy.
I regularly committed code that I was happy with, and attempted to always write meaningful messages to explain the progress.
Early on in the project I accidentally pushed a secret variable to github. I corrected the error and changed the secret key to ensure sesitivity with the project going forward. I have made sure that no passwords or sensitive information are committed to the repository using environmental variables and .gitignore for managing secret keys and configurations.
This Django project was deployed with Heroku and can be viewed here: https://capstonehotel-1327201ddfdf.herokuapp.com/
I navigated to https://dashboard.heroku.com/apps and set up a new project. I clicked on settings > config vars > reveal config vars and added secret keys.
Back to VS terminal:
pip3 install gunicorn ~=20.1
pip freeze > requirements.txt
I then created a Procfile in root directory and added gunicorn to run the website and created a .python-version file to specify version 3.12 for build. Herokuapp was added to ALLOWED_HOSTS and then I ran git add, commit and push.
I returned to Heroku, linked to Github repo and EcoDynos. I then scrolled to the bottom of the page and deploy from main branch. Once the build was completed, I was able to view my application by clicking 'open app'.
I regularly deployed throughout the development to check how the changes I was making looked on the Cloud Platform.
I have kept all secret information in an env file that has been added to .gitignore. Config vars were then added to Heroku for secure deployment.
I have implemented a number of Custom Data Models in this application.
- Room allows admin to add rooms for users to view and book
- RoomBooking allows users to add, edit and delete bookings
- AboutUs generates content for the about page
- ContactRequest allows users to contact the hotel
Copilot helped me to set up the CRUD functionality on the booking app. I asked AI to talk me through each step I needed to have functional CRUD. I reviewed the suggested code at each stage to ensure that I understood what it was telling me to do. This helped save time with the set up and reduce the likelihood of me missing cruitial steps. AI helped in the learning as when I later came to set up the about app, I did not need AI step by step, although was useful for troubleshooting when code was not generating as expected.
I have used AI by copying in error codes. Although I have asked it, it often has not given me the solution and I referred to Code Institute instructors instead.
I thought that the sign up, sign in and logout pages affected user exeperience. I prompted AI to tell me how to add the base.html styling to these pages and had AI generate the code within them to save me time and to keep styling the same throughout the website.
After receiving disappointing scores in the Lighthouse test, I used AI to identify where ARIA labels should be included then went on to manually add required labels. Also following feedback from the Lighthouse test, I used AI Pair Programming to improve the embedded map in about.html.
I experimented with Co-pilots ghost text to generate the automated testing, for example test_forms.py in the booking app. I found this very useful as a time saver and in helping my understanding of what the automated tests should include.
AI has been extremely useful in my development process, particularly by saving time and explaining complex code in clear and straightforward ways. While there were opportunities to make more extensive use of AI throughout the project, I made a conscious decision early on to limit my reliance on it as I wanted to fully understand my project and increase my learning as a training software developer.
I was completely new to coding before starting the bootcamp, so being able to build a functional full stack application after just 16 weeks of learning feels like a huge achievement. This project reflects not only how much I’ve learned, but also the confidence I’ve gained along the way. I would like to extend particular thanks to Tom, Alex and Mark at Code Institute for their guidance and support, as well as to my cohort on the Full Stack Software Development bootcamp for the encouragement and shared learning along the way.










