This is a Code Institute student project for Milestone 4, built to satisfy the requirements for the EKC Training Diploma (Level 5) in Web Application Development.
This project has been created in order to provide a community CRUD application on a deployed interactive website. The project was built using Gitpod.
The information has been presented in a way that ensures the users achieve their goals of:
- understanding what the site's function is
- understanding how to create, read, update and delete their own records or posts
- being able to register, log in and log out of this community site
The site also enhances the owner's goals by:
- showcasing their database design skills
- showcasing their Python programming skills
- showcasing their Django skills
- showcasing their back-end development skills by allowing users to change data in a PostgreSQL relational database with the aid of the Django web-framework.
- The technologies used were HTML, CSS, Python, Django and PostgreSQL.
- This interactive back-end project contains pages to enable users to create, read, update and delete user records in a relational database
- This README.md file explains what the project does and the value it provides for the users
- Version control is provided by Git and GitHub
- External code, libraries, templates, images, information, etc. will be listed in the Credits, at the bottom of this README.
- This project is deployed via Heroku. The code stored in a GitHub repository, whilst the data is stored in the relational PostgreSQL database hosted by ElephantSQL.
View the demo video on YouTube.
The aim of the project is to provide a supplementary app for local hospitality businesses offering a food takeaway service. Whilst many of these business offer an online table booking service, they do not have a select, pay and collect (or delivery) facility for takeaway food.
This site is created for my friend Jason Firth who owns the Luca Loves PIZZA mobile takeaway service for Warwickshire and the West Midlands. He travels with his pizza van to local events and festivals. Jason usually operates the service by himself and at the moment mainly takes orders via WhatsApp messenger, but it would make life easier if this part of the business could be automated.
This app is inspired by Zari Restaurant in Crawley, West Sussex. I used their online takeaway facility many times, whilst working away. I would order my meal, pay for it and select a time slot for collection on the way home.
The site is designed to be responsive and accessible on a range of devices, making it easy to use for potential users.
β denotes current features
"As a user, I would like to _____________________________"
- β add, update or delete items from shopping bag.
- β keep my information secure.
- β order and pay for products.
- β see my order history.
- β use the site without logging in.
- β subscribe to a newsletter.
- β view the site owner's blog.
"As an owner, I would like to _____________________________"
- β build a Django app.
- β allow users to store their data via the app.
- β build a bolt-on ecommerce app to assist local food businesses, which do not have a takeaway order and payment section.
- β build an app to be visually attractive.
-
This app was influenced by the Code Institute full stack e-commerce tutorial for Boutique-Ado, by Chris Z.
-
What is a CRUD app? This type of app allows the user to create, read, update and delete records or posts in a database via graphical interface. In this case the PostgreSQL database is hosted by ElephantSQL and as the app is developed with Python 3.8, the graphical interface is provided by HTML5 and the mini-framework, Django 3.2 with Bootstrap v4.6.
-
Why this app? Many restaurants have a takeaway service where customers can order over the telephone, but surprisingly very few offer an online order, payment and delivery/collection service. With the arrival of the pandemic and the shortage of hospitality staff, may establishments would benefit from such a service. Many local businesses are on a strict budget, so this app is designed to be a bolt-on feature built by ClickCollect for use with any restaurant website. This particular site was designed for a mobile pizza van service located in the West Midlands. The business owner's photographs are used to display the products for sale. A search facility on keywords allows the user to search though the products on offer. The site does not require login, but profile and checkout pages do. All products are visible to every one, but only the site owner (superuser) can add, edit or delete the the product details.
-
View the project design flowchart to see which Django apps are associated with which templates of the app:
- Bootstrap 4.6 is popular framework for building responsive, mobile-first sites, with jsDelivr and a template starter page..
- jQuery 3.5.1 was used for minimal JavaScript programming.
- Django 3.2.19 is a web framework used to render the back-end Python with the front-end Bootstrap.
The following Bootstrap colour scheme was chosen for simplicity, readability and lends itself nicely to the subject of multi-coloured flame baked pizzas.
Bootstrap v4.6 uses native font stack that selects the best font-family for each OS and device. For a more inclusive and accessible type scale, it uses the browserβs default root font-size (typically 16px) so visitors can customize their browser defaults as needed.
In general, all pages have the Bootstrap white background with dark grey or black text. Added splashes of colour are provided by the Bootstrap red colour class '.bg-danger', hex: #DC3545.
View the wireframes PDF here.
The pages contain the same functionality and look the same on every device, with the exception to the menus and the number of product cards displayed across the screen.
- Home
- Navigation
- Navigation (Logged In)
- Products
- Product Details
- Product Add (Admin Login Only)
- Product Edit (Admin Login Only)
- Shopping Bag
- Checkout
- Checkout Success
- Blog
- Blog Article
- Newspaper Subscription
- Sign Up / Register
- Sign In / Login
- Profile (User/Admin Login)
- Sign Out / Logout
- Home
- Navigation
- Navigation (Logged In)
- Products
- Profile (User/Admin Login)
- Other Pages - same as for tablet
- Home
- Products
- Product Details
- Shopping Bag
- Other Pages - same as for tablet
This projects uses ElephantSQL which offers PostgreSQL as a service.
Database Entity Relationship Diagram (PostgreSQL)
In Django, data is created in objects called Models, which are actually tables in a database. The following are the custom built models for this app. Models generated by allauth or Django Admin are not covered here.
Blog Model
The Post model has the following fields:
-
title: A character field (CharField) for the title of the blog post with a maximum length of 200 characters. It must be unique.
-
slug: A slug field (SlugField) used in URLs to represent the post with a maximum length of 200 characters. It must be unique.
-
author: A foreign key field (ForeignKey) that relates the blog post to a user from the User model. The on_delete=models.CASCADE specifies that if the related user is deleted, all their blog posts will also be deleted. The related_name='blog_posts' provides a reverse relation for the user model.
-
updated_on: A DateTime field (DateTimeField) that automatically updates whenever the post is modified.
-
content: A TextField that holds the content of the blog post.
-
created_on: A DateTime field that automatically records the date and time when the post is created.
-
status: An Integer field (IntegerField) that represents the status of the post, with two choices: "Draft" (status=0) and "Publish" (status=1). The default value is set to "Draft".
The Post model also defines a nested class Meta, where the ordering of the blog posts is set to be in descending order of the created_on field.
Finally, the __str__
method is defined to return the title of the blog post as a string representation when the object is referenced.
Checkout Models
This Python code defines two models for handling orders and order line items in a Django web application:
-
Order model: This model represents an order made by a user. It includes various fields for storing order details such as order_number, user_profile, full_name, email, phone_number, country, postcode, town_or_city, street_address1, street_address2, county, date, delivery_cost, order_total, grand_total, original_bag, and stripe_pid. The model also defines methods for generating a random order number, updating the total amount of the order (including delivery costs), and overriding the save method to set the order number if it hasn't been set already.
-
OrderLineItem model: This model represents individual line items in an order. It contains fields like order, product, product_mod, quantity, and lineitem_total. The model includes a save method to set the line item total based on the product price and quantity, and it updates the order total accordingly.
These models are related through foreign keys, and they facilitate storing and managing order data for the web application. The __str__
methods in both models provide string representations of the order and line items when referenced.
Products Models
This Python code defines two models, Category and Product, for handling categories and products in a Django web application:
-
Category model: This model represents product categories. It has fields for name and friendly_name. The name field stores the name of the category, and the friendly_name field stores an optional user-friendly name for the category. The model provides a method get_friendly_name() to return the friendly name if available. The
__str__
method returns the name of the category as its string representation. -
Product model: This model represents individual products in the web application. It includes fields such as category, sku, name, description, has_mods, price, rating, image_url, and image. The category field is a foreign key that links the product to a category from the Category model. The
__str__
method returns the name of the product as its string representation.
Both models utilize Django's models.Model class for defining the fields and behavior. They help in managing category and product data and establishing relationships between products and their categories.
Profiles Model
This Python code defines a UserProfile model and a signal receiver function to create or update user profiles when a new user is created or an existing user is saved.
-
UserProfile model: This model represents a user profile and contains fields for maintaining default delivery information, including user, default_phone_number, default_street_address1, default_street_address2, default_town_or_city, default_county, default_postcode, and default_country. The user field is a one-to-one relationship with the Django User model to associate each user with their profile. The str method returns the username of the associated user as its string representation.
-
create_or_update_user_profile signal receiver: This function is connected to the post_save signal of the User model. When a new user is created, it automatically creates a corresponding UserProfile instance. For existing users, it updates the UserProfile instance to ensure it stays synchronized with the associated user.
The code effectively sets up a one-to-one relationship between the User model and the UserProfile model, allowing each user to have a profile with default delivery information and order history. The signal receiver ensures that user profiles are created or updated as needed when user instances are saved.
Subscribe Model
This Python code defines a Django model named SubscribedUsers to store information about subscribed users. The model includes the following fields:
-
name: A character field with a maximum length of 50 characters to store the name of the subscribed user.
-
email: An email field with a maximum length of 254 characters and marked as unique=True to ensure each email is unique in the database. It stores the email address of the subscribed user.
-
created_date: A DateTime field with the default value set to the current date and time using timezone.now. It represents the date and time when the user's subscription was created.
The __str__
method is defined to return the email address of the subscribed user as its string representation. This model is suitable for maintaining a list of subscribed users with their names, email addresses, and the date when they subscribed.
-
This app consists of the following pages (no login required):
- Home
- Products
- Product Details
- Shopping Bag
- Checkout
- Checkout Success
- Blog List
- Blog Article
- Newspaper Subscription
- Sign Up
- Sign In
-
User/admin logged in pages for:
- Profile
- Password Reset
- Sign Out
-
Additional admin (superuser) only pages for:
- Add Product
- Edit Product
-
And a further set of in-built Django admin pages for user and app management
Navigation section will be the default responsive Bootstrap one.
-
Desktops
The main menu items in bold:
- ClickCollect branding for navigation to the Home page
- Search our site box
- My Account with dropdown menu for:
- Register
- Login
- Product Manage (Administrator Only)
- My Profile (User Login)
- Logout (User Login)
- Shopping Bag
will be inline with the Search box and fixed across the top of the screen. Underneath will be Product and More menu items:
- All Products with dropdown menu for:
- By Price
- By Rating
- By Category
- All Products
- Pizza & Calzone with dropdown menu for:
- Meat
- Vegetarian
- Vegan
- All Pizza
- Drinks with dropdown menu for:
- Cold drinks
- Hot Drinks
- All Drinks
- More... with dropdown menu for:
- Our Blog
- Subscribe
which will be inline and fixed just above the red FOLLOW US on Facebook banner.
All dropdown menu items will have dark grey text on a white background and on hover, a light grey backgound.
-
Mobiles
-
will feature the collapsed Bootstrap navigation with a hamburger icon inline along the top of the screen with:
- Search icon with dropdown search box
- My Account with dropdown menu for:
- Register
- Login
- Product Manage (Administrator only)
- My Profile (User Login)
- Logout (User Login)
- Shopping Bag
-
selecting the hamburger icon will reveal a dropdown menu with black text on a white background:
- All Products with dropdown menu for:
- By Price
- By Rating
- By Category
- All Products
- Pizza & Calzone with dropdown menu for:
- Meat
- Vegetarian
- Vegan
- All Pizza
- Drinks with dropdown menu for:
- Cold drinks
- Hot Drinks
- All Drinks
- More... with dropdown menu for:
- Our blog
- Subscribe
- All Products with dropdown menu for:
-
Anyone (guest, member, administrator) can view this page which features a hero image with a call to action ORDER NOW button.
The products are displayed as cards containing the item image with the following summary:
- item name
- price
- category
- rating out of 5
Clicking the image will take the user to the product detail page. This page also contains a Sort By box for ordering the items.
Only the administrator can view the links to Edit (blue) or Delete (red) a product.
Only the selected product is displayed with a larger image and the same details. In addition the following is seen:
- item description
- quantity adjustment box
- add to bag button
- keep shopping button
Only the administrator can view this page which contains the add product form.
The following fields are displayed: (*
mandatory)
- category dropdown select
- sku
- name*
- description*
- price*
- rating
- image url
with the buttons:
- select image
- cancel
- add product
Only the administrator can view this page which contains the edit product form.
The following fields are displayed: (*
mandatory)
- category dropdown select
- sku
- name*
- description*
- price*
- rating
- image url
with the buttons:
- select image
- cancel
- add product
Users can see which items they have added to their bag. Here, they can:
- view the grand total
- update the item quantity
- remove the item
- keep shopping
- proceed to secure checkout
Checkout is completed via secure Stripe Payments. Users fill in their card details and have the option to save their details in their profile. Payment success is issued via a checkout success page and email confirmation, whereas failure is notified by red text underneath the card number.
Logged-in users can view a past order page from their profile, with the following information:
- email address used for order confirmation
- order information
- order details
- credit card address
- billing information
Blog contains a list of articles displayed in reverse chronological order. Selecting the READ MORE button takes the user to the more informative current blog article.
Anyone can subscribe to the business newsletter email which keeps users updated on future events.
Anybody can register for free and create a unique profile to store their own order history.
This facility is created using the Django-allauth package built on top of Django's own authentication and authorisation framework. This provides a comprehensive set of tools to handle user authentication and registration in Django projects.
It is important that unauthorised users are denied access to certain pages. Personal profile pages contain credit/debit card address details, full name, phone number and email address - information that should be protected. At the moment, this app does not show users the names of other users - this makes it difficult to attempt access to personal accounts. @login_required decorators are used to ensure only logged in users have access to appropriate pages.
The administration pages for the site owner are protected from other users by creating a superuser account during project installation. A flag is used in the database to indicate if a certain registered user is a superuser/admin. This method is much better than creating a superuser with username of admin, which gives hackers half the information required - they only have to guess the password.
See the Testcases section for how the defensive programming is implemented.
An inbuilt Django decorator protects user profiles. Only the current logged-in user can view the past order detail page - which is actually the same page as checkout success, or update default address information.
This is a separate page where the user either confirms to signing out or cancels the action.
This page replaces the standard Django Page Not Found with one matching the site design and a Go Home button.
This page replaces the standard Django Internal Server Error page with one matching the site design and a Go Home button.
- Allow users to 'rate' or 'like' products
- Allow users to register via social media accounts - this is provide in the app but due to time constraints is not yet activated
- Add special offers and discounted items
- Send out an actual newsletter email
- Offer a delivery service when the business expands to a certain level
- Let the customer choose a time slot for collection
- Offer dietry requirement options
- Cloud developer platform from Gitpod.
- IDE integrated into Gitpod from Visual Studio Code.
- Debugging assisted by Chrome Developer Tools.
- Version control integrated into Gitpod from Git.
- Wireframes from Balsamiq.
- Native font stack from Bootstrap.
- Colour palette generated by Bootstrap.
- Icon library and toolkit from Font Awesome 5.
- Online photo editor from Pixlr.
- Stock photos from Unsplash.
- Product photos from Jason Firth
- Showcasing the site on different devices by Bytes
- Paint from Microsoft
- Snip and Sketch from Microsoft
- PDF Reader from Adobe Acrobat Reader
- Flowchart by diagrams.net/draw.io
- PostgreSQL ERD created by DbSchema
- Python code summaries and test files generated by ChatGPT from OpenAI
- Demo video for YouTube created on Clipchamp
-
- HTML5 as the base for markup text.
-
- CSS3 for custom styling the site.
-
- jQuery 3.5.1 for JavaScript functionality.
-
- Bootstrap 4.6 is a popular framework for building responsive, mobile-first sites.
-
- Python 3.8.12 is a high-level, general-purpose programming language.
-
- Django 3.2.19 is a web framework written in Python.
-
- Django-allauth 0.41.0 for authentication and authorisation.
-
- Heroku is used as "Platform as a Service" (PaaS) for app hosting.
-
- PostgreSQL is used as a relational database plugin via Heroku.
- HTML validation from W3C
- CSS validation from Jigsaw (W3C)
- Python validation from CI Python Linter
- Tool For Style Guide Enforcement from Flake8
- JavaScript validation from JSHint
- Site audit by Lighthouse
- Temporary email account for testing from Temp Mail
See the document TESTING.md for the code validation, site evaluation and manual tests.
See the document DEPLOYMENT.md for local and Heroku deployment.
A huge thank you to the following people and organisations, because without you, the website would not have been produced in it's present form.
Heroku deployment instructions from Code Institute graduate Joy Zadan
Readme styling from Tim Nelson's project Unicorn Attractor
Markdown Cheatsheet from Adam Pritchard
Favicon created on favicon.cc
Emoji shortcodes from Ikatyang on GitHub
GitHub static badges from Shields.io
Although this project is the work of the author, the code is based on the Boutique Ado Tutorial by Chris Z for Code Institute.
Other code sourced from or inspired by others have references embedded as links throughout this document and indicated by the active blue text links.
The Blog App code is based on the Djangocentral tutorial Building A Blog Application With Django by Abhijeet Pal
Subscription page code based on the Python Lessons tutorial Introduction no Subscribers and Newsletter #18 by Rokas Liuberskis
Rachel Furlong - EKC Training Course Facilitator, for generous support and advice.
Rohit Sharma - Code Institute Mentor, for the continuous feedback and guidance in industry standards.