Nibble Kitchen is an e-commerce site offering various confections.
The site is fully responsive and was built using the Django framework in Python.
The live site has been deployed here.
The payment system used for the site is called Stripe. The system is set up in a 'dummy' mode and will not accept real card details.
To test this functionality, please use the card details that can be found here.
-
- As a user, I want to navigate round the site easily to locate the products I want.
- As a user, I want to view a list of all available products.
- As a user, I want to be able to view more details on a product, such as price, ingredients and reviews.
- As a user, I want to be able to refine my search with categories.
- As a user, I want to be able to sort products by price, review or name.
- As a user, I want to be able to easily contact the site owner if needed.
- As a user, I want to be able to see all ingredients contained within the product, including any allergens.
-
- As a user, I want the option to register for an account, allowing me to save my details and see previous orders.
- As a user, I want to receive confirmation emails to confirm my registration.
- As a user, I want the ability to be able to log in and out, and be able to easily work out my current login status.
- As a user, I want to be able to recover my account information in the event that I forget it.
-
- As an admin, I want to be able to add products easily in a format consistent with the rest of the site.
- As an admin, I want to be able to edit products easily to ensure the customer is being shown the most up to date information
- As an admin, I want to be able to delete discontinued products, or mark seasonal products out of stock when not available.
- As an admin, I want to be able to easily manage the images in the gallery, and update the site policies.
- As an admin, I want to be able to add and update the ingredients for products, and mark any allergens appropriately.
-
- As a user, I want to be able to add items to my cart, allowing me to store things until I'm ready to complete my purchase.
- As a user, I want to be able to view my cart so I can see the current running total of my potential purchases.
- As a user, I want the ability to update the quantity of the items in my cart easily.
- As a user, I want an easily viewable total to allow me to monitor my overall spend.
- As a user, I want to be able to complete the purchasing journey, without the need to register if I do not wish to.
- As a user, I want to receive confirmation of my order so I know my order was placed successfully.
- As a user, I want to be able to view my order history so I can review past purchases.
-
- As a user, I want to be able to leave a review of products to share my experience with other customers
- As a user, I want to be able to easily connect to the business' social media pages to keep up to date.
- As a user, I want to be able to easily contact the site owner if needed.
-
The decision was made to keep the colours as simple as possible for the website, with the main content being either black text on a white background, or vice versa.
This is due to cakes and confectionary being inherently colourful. By reducing the colour palette to the most basic possible helps draw attention to the products displayed, and the colours within.
-
The Roboto font from Google Fonts is used throughout the site on all content.
This font was chosen due to it's readability, popularity and familiarity, with it being the chosen font for a number of products produced by Google.
-
All product images have been taken from the current website for Nibble Kitchen, with permission from the owner.
Other images used throughout the site were chosen from the website Unsplash and were chosen to fit the overall theme of the website.
Image credits can be found in the Media section of this Readme.
-
The database schema for the project was:
The full image can be viewed here
-
-
- To allow easy navigation around the site, the navbar is fixed to the top of each page and contains links to all areas of the website, with the exception of the information in the footer.
- The navbar collapses to a hamburger menu once the window width drops below 992px to ensure all information is displayed comfortably to the user.
- All links, with the exception of About Us and Contact Us, make use of Bootstrap's dropdown plugin. Upon a link being clicked, more options are shown to the user.-
-
Search Bar
- The search bar is located in the middle of the navbar, above the links and can be used to search the site for products.
- The search term entered will be used to search the database for any products with matching information in either the product title, product description or product ingredients.
- On screens with a width below 992px, the search bar is hidden and can be displayed by clicking on the 'Search' button that is present in the navbar.
- JQuery is used to check the content of the search bar. If no search term has been entered, a warning is shown to the user for 5 seconds.
-
Account
- A user icon is located in the top right of the page, allowing the user access to manage their account and personal information.
- Clicking on the icon displays a dropdown menu using Bootstrap's dropdown plugin with a number of options
- Login & Register are displayed if the user is not logged in.
- My Profile & Logout are displayed if the user is logged in.
- Admin Dashboard & Add Product are displayed if the user is a superuser.
-
Cart
- A cart icon is also located in the top right corner of the page displaying the value of the current contents of the cart, and the number of items that are present in the cart.
- Clicking the cart icon will take the user to the cart page where they can complete their shopping journey.
-
Banner
- A banner is displayed below the navbar advising the user on the current offer for free delivery.
- If the user does not have any products in their cart, a message is shown stating 'Free delivery on orders over £65'
- If the user does have items in their cart, the message is updated to notify the customer how much more they need to speed to ready the £65 free delivery limit.
-
-
- The home page has been designed with a minimalist appearance, containing only a hero image, a message, and a button directing the customer to view products on the site.
- The hero image can be seen in the Media section of this readme.
- The message informs the user of the purpose of the site in a succinct manner, with the action of the button being made obvious by the label contained within.
-
- Registration Page
- The registration page is used by users to create a new account for the site.
- Form validation is used to ensure all fields on the form are completed. If this validation fails, a message is shown to the user and the form is not submitted.
- Once form validation has passed, the form will be submitted and the user will receive a confirmation email to verify their account.
- Login Page
- The login page is used for users with an existing account to log in to the site.
- If the user has not verified their account by clicking on the link in the email they are sent, they will be unable to log in.
- A 'Forgot Password' link is present for users to recover their account in the event that they cannot remember the required information to log in.
- Logout page
- The logout page is used by users to log out if they are signed in, removing their session information.
- The user will be taken to a confirmation page upon clicking the 'Logout' link, to ensure this is the action they wish to take.
- Registration Page
-
-
Heading
-
Delivery Information
-
The delivery information section shows any stored address information for the user.
-
The information can be updated on this page, and these change will be used to autocomplete the delivery address when placing an order.
-
The information displayed in this section can also be updated when the user completes the shop journey if they check the 'Save this delivery information to my profile' box.

-
Order History
- The order history section displays all previous orders placed by the logged-in user.
- This section will display the order number, date of order, items ordered, quanitity ordered and the overall total.
- Clicking on the hyperlink tag surrounding each order number will direct the user to a more detailed summary of the order.

-
-
-
Products Page
- The products page displays a list of available products in a selected category, search term or, if the correct option is selected, all products are shown.
- Each product card show an image of the product, the price (or price range), the category in which the product resides and the rating. If no ratings are available 'No Rating' is shown in its place.
- If a product is on sale, the original price will be shown with strikeout styling applied, the sale price will be shown and a small badge will be placed next to the prices to show the percentage of discount being given.

-
Sorting
- The sort-by box is located in the top right of the products section on screen sizes above 768px width, and in the centre below 768px width.
- Clicking on the box displays the sorting options available to the user.

- Within
views.py, an if statement is present to check if the sortkey containsdesc. Ifdescis present,nulls_last=Trueis appended to the end of the search term to ensure products with ratings are shown before products with no ratings.
-
-
-
Product Info
- The product info section of the product details page shows all the important information related to each product.
- The left part of the product info section is taken up by an image of the product. The image can be enlarged upon clicking to enable a better view. This is done within the page using bootstrap, rather than opening a new tab.
- The name of the product is displayed at the top of this section and is also added to the title of the page.
- Below this, the price of the product is shown.
- If the product is on sale, the original price will be shown with strikeout styling applied, the sale price will be shown and a small badge will be placed next to the prices to show the percentage of discount being given.
- If the product has sizes, the prices are updated appropriately using JQuery. The values for these prices are obtained from a seperate file which, in turn, queries the database for the correct prices. This ensures the same code can be reused throughout the site.
- The category for the current product is shown next, with an underline style applied to indicate a hyperlink. Clicking on this link will direct the user to the products page for that category.
- The Rating for the product is shown next. The rating is calculated by dividing the sum of all reviews by the number of reviews. If there are no reviews for a product, 'No Rating' is shown instead.
EditandDeletebuttons are shown next to the rating if the current user has superuser privileges, allowing the requested action to take place.- If the product has different sizes available, the
Sizefield will be shown allowing the user to pick between Small, Medium, or Large. This is mainly applicable for the cake jars. - The
Quantityfield is shown for all products and allows the user to increment or decrement the value either with the provided buttons, or by typing directly into the box. Javascript is used to check if the value is above 99, which will return the max value to 99 if true. - A pair of buttons with the text of
< Keep ShoppingandAdd to Cartare displayed as the element of the product info section, respectively. The< Keep Shoppingbutton will return the user to the main products page, with theAdd To Cartbutton adding the item into the user's cart before returning them to the same page.
-
Ingredients
- The Ingredients section is the first tab within the bottom section of the Product Details page. It begins with information advising that all allergens are marked in bold.
- The ingredients are stored in the database for each product and are retrieved to be displayed on the page. This was done to ensure that any updates to allergens in the future take effect site wide and to ensure customers with allergens have the best information possible.
- Below the ingredients section is a disclaimer, providing a list of allergens used and warning that items are baked in a single kitchen and that cross contamination between allergens is possible.
-
Customer Reviews
- The Customer Reviews section displays any reviews that have been left by customers previously. If no reviews have been left, the user is instead shown a message stating:
There aren't any reviews for this product. Be the first to leave a review!, with a link being provided to theLeave A Reviewtab. - If reviews are present in the database, the rating is obtained and the relevant rating image is displayed alongside the title of the review. Below this is the username and date on which the comment was made, followed by the comment itself.
- Superusers and the original user who posted the comment have the ability to delete the comment if required. No user has the ability to edit user reviews to ensure the reviews section is perceived as trustworthy.
- The Customer Reviews section displays any reviews that have been left by customers previously. If no reviews have been left, the user is instead shown a message stating:
-
Leave A Review
- The final section on the Product Details is for the user to leave a rating and review of the product.
- The first part of the form allows the user to leave a rating between 0.5 and 5.0 stars. The rating already selected by the user is highlighted in
Yellow, with aGreenhighlight being applied to any stars upto where the user is current highlighting with the mouse. - The
TitleandContentsections of the form allow the user to provided a title and the content of their review respectively. - Following the form being validated successfully, the form is submitted and the rating, title and content are submitted to the database. Along with this information, the product ID, date, time and user ID is also stored.
- If a user has already left a review, they will instead be shown a message stating
You've already left a review for this product!
-
-
- Whether
AddingorEditinga product the user is shown the same form, however theEdit Productpage will already be populated with data. - Due to the similarities of the form, I will first discuss the form itself before going into the different between the two pages.
- Both pages
REQUIREthe following information:- Category
- Name
- Description
- If the product
Has Sizes - Price (This is used as the Small price for products with sizes, or standard price for other products)
- Sale Price (This is used in the search function for the purpose of ensuring prices are sorted correctly)
- Ingredients (The Sorted M2M Filter Horizontal Widget was used to enable vertical sorting of products, replacing the standard
Hold Ctrl and Clickselect menu.)
- All other fields on the page are optional.
- The only other difference between the pages, other than the ones already mentioned, is the additional modifying of the title when editing a product.
- Whether
-
- The cart is split into two main elements
- Products Section
- Total Section
- Products Section
- The products section is also split down further into 5 sections:
- The
Productsection displays an image for each of the products contained within the cart. - The
Product Infosection displays the name of the product chosen. If the product has a size value, if will be displayed on the following line, otherwise this value will not appear. Finally the SKU of the product will be displayed. - The
Pricesection displays the unit price for the item, and size if applicable, chosen. - The
Quantitysection displays the current quantity of the product chosen, with controls provided to allow the user to update the quantity if they wish to. - The final section is the
Subtotalsection which multiplies the value from thePricefield with the value of theQuantityfield to calculate the total being paid for this item.
- The
- The products section is also split down further into 5 sections:
- Total Section
- The
Cart Totalfield calculates the sum of allSubtotalvalues within the cart to determine the overall total value of products. - The
Deliveryfield displays the value of theCart Totalfield multiplied by theSTANDARD_DELIVERY_PERCENTAGEvalue fromsettings.py. This is currently set to 10%. - The
Grand Totalfield shows the sum of theCart TotalandDeliveryfields. - Below the
Grand Totalfield is a notice to the customer informing them of the required further spend for them to receive free delivery of their products. This value is calculated by subtracting theCart Totalvalue from theFREE_DELIVERY_THRESHOLDvalue set insettings.py. The delivery cost is not included in this calculation. - The final part of the
Total Sectionare theKeep ShoppingandSecure Checkoutbuttons. Like theProduct Detailpage, the< Keep Shoppingbutton will return the user to the main products page, leaving the current products in the cart as they are. TheSecure Checkoutbutton will navigate the user to theCheckoutpage which is described in more detail in the next section.
- The
- The cart is split into two main elements
-
-
The Checkout page is split into two main columns: Customer Details & Order Summary. The Checkout app also features a
Checkout Successpage once the order has been submitted, and a loading overlay whilst the order is being submitted.-
Customer Details
-
The first section of this column asks for the customer to provide their name and email address. The name is required to ensure the correct delivery information is added to the package prior to it being dispatched, with the email address being used to send order confirmation to the customer. The customer is not required to sign in to complete their order, however if they are signed in, and have saved their delivery information, these fields will be populated.

-
The box below this uses the Address Finder API provided by Woosmap. This has been configured to only search for address within the UK as this is where the business is based. The user has the option of typing their address into this box and clicking the corresponding result, with the information then being used to fill the form below.
-
If the customer does not wish to use the Address Search feature, they can manually enter their details into the address details form, with the following details being required:
- Phone Number
- Street Address
- Town or City
- Post Code
-
If the user is already registered, and has delivery information stored, this information will be automatically populated.
-
The user also has the option to update or save their delivery information, which can be used to populate the form for future orders by ticking the checkbox below the form.

-
The payment element of the checkout app is provided by Stripe. Stripe is used as a secure payment method, and means that no card information is stored within the website database, with all information being provided back to the website via Webhooks.
- If
payment_intent.succeededis returned via the webhook, the order will be submitted. - If
payment_intent.payment_failedis returned via the webhook, the order is not submitted, with the user being returned to the checkout app, with a message provided stating the order has failed.
- If
-
The following card details can be used to test the payment functionality of the Checkout App:
Scenario Card Number Expiry Date CVC Postal Code Payment Succeeds 4242 4242 4242 4242 Any Any Any Payment requires authentication 4000 0025 0000 3155 Any Any Any Card declined - Insufficient Funds 4000 0000 0000 9995 Any Any Any -
The final elements of the
Customer Detailssection are theAdjust CartandComplete Orderbuttons. The< Adjust Cartbutton will return the user to the cart app, with any details entered into the form being lost, unless already saved to the users profile. TheComplete Orderbutton will first submit the payment information via theStripewebhook. -
Once
payment_intent.succeededis received the order will be submitted and the user will be navigated to theCheckout Successpage.
-
-
Order Summary
- The order summary section shows a compacted version of the data displayed in the
Cartapp. - The title of the
Order Summarysection shows the number of products contained within the cart. - Each item within the cart is listed, including the size (if applicable) and quantity.
- Unlike the
Cartapp, in theOrder Summaryview only the Subtotal for each product is shown. - As with the
Cartapp, the Order Total, Delivery charage and Grand Total values are shown to give the customer the opportunity to confirm everything looks correct before their order is submitted. - Using
Stripewebhooks, the database is queried to confirm the order was created successfully. If the order cannot be found, the webhook handler will created the order in the database using the information sent with the original payment intent.
- The order summary section shows a compacted version of the data displayed in the
-
Loading Overlay
-
When the
Complete Orderbutton is clicked and the form validation on the checkout page is passed, a loading overlay is displayed preventing any other changes to the form, or any further form submissions. -
The loading icon is provided by Font Awesome, using the
fa-cake-candlesclass, and is animated with thefa-beatclass.
-
-
Checkout Success
- Once all of the previous steps have been completed, the
payment_intent.succeededresponse has been received and confirmation that the order has been created in the database, the user is taken to theCheckout Successpage. - Above the order summary itself, a message is shown advising the user that a confirmation email will be sent to them, confirming the details of their order.
- The user is then provided with the
Order NumberandOrder Date, which can be used in the event the customer needs to contact the business, speeding up the process of retrieving the relevant order. - The
Order Detailssection provides further confirmation of the products that have been ordered, including quantity and individual unit price. - The
Delivering Tosection displays the address information provided by the customer. This is important as it gives the customer a chance to check over the details and to confirm that they are correct. - The final section within the order summary box is the
Billing Infosection, providing a further recap of the Order Total, Deliverty charge and Grand Total of the order. - Below this is a message advising the customer to get in touch if they spot any errors on the form, ensuring that the corrections can be made as soon as possible.
- Finally, a button containing the text
Take me back to the cakes!is displayed and returns the user to the mainProductspage.
- Once all of the previous steps have been completed, the
-
-
-
- The image used on the 'About Us' page was made available via Unsplash by the user American Heritage Chocolate and is used under the Unsplash License.
- The page gives a brief history of the business and the content is set using Django Quill Editor. This allows easier editing for the business owner without needing to have any knowledge of HTML or CSS.
- The About Us page ends with a reminder to contact the business with any questions or queries, hopefully increasing engagement and leading to more business.
-
-
The
Contact Uspage is linked to from various other places on the website and allows users to contact the business with any query they may have. -
The form was purposefully left as basic as possible to give maximum flexibility to the user. The form consists of 3 text fields (Email, Subject and Message.)
-
Once all sections have been completed and the
Submitbutton has been clicked, the information is stored in the database and the user is directed to theContact Successpage. -
The
Contact Successpage contains a message statingThank for getting in touch with us. We've got your message, and we'll be in touch as soon as possible., with a button returning the user to the main products page. -
The messages sent by users can be viewed from the admin panel, where the option is available to mark a message as actioned, allowing other people who may use the admin panel to see which messages have/have not been responded to.
-
-
-
Toasts appear in the top-right corner on the screen when any information needs to be relayed to the user. The toasts appear using a CSS animation which alters the location of the toast.
-
The toasts display messages under the categories of
Success,Alert,WarningandError. -
The toasts have slightly different designs depending on the type of toast used.
- The
Alert,WarningandErrortoasts all share the same design of a dark header and dark body with only the colour of the icon on the alert change. - The
Successtoast instead has a dark header and light body. This is due to the amount of information displayed on theSuccesstoast when items are added to the basic and aids readability for the user.
- The
-
-
-
The footer is displayed on all pages other than the main landing page of the website, and sits at the bottom of each page.
-
The top part of the footer is a full width div containing links to the Social Media pages for the business.
-
The lower section of the footer is split into three columns with the first having a short
About Ussynopsis. The title of the column also links to theAbout Uspage, but is not underlined due to the link also being available in the navbar. -
The middle column contains
Useful Linkswhich direct to individual pages for the Refunds & Returns Policy, Postage & Packaging Policy and Privacy Policy. Like theAbout Uspage, all content on these pages is set using Django Quill Editor. This allows easier editing for the business owner without needing to have any knowledge of HTML or CSS. -
The third and final column contains contact information for the business, with a
mailto:link being used to highlight the email address. -
Icons provided by Font Awesome throughout the footer.
-
-
-
Error 404 Page
If the user navigates to a page that does not exist, the 404.html page will render. This page has the same basic layout as the home page of the site, but displays different text content. The button, however, still returns the user to the main products page.
-
Error 500 Page
If the user navigates to a page that causes a response the server does not know how to handle, the 500.html page will render. This page has the same basic layout as the home page of the site, but displays different text content. The button, however, still returns the user to the main products page.
-
Testing and results can be found in the TESTS.md file.
-
-
Before you start, a repository (repo) is required on Github which can be created in a number of ways.
-
- Log into Github.
- In the top left corner of the page is a column titled 'Recent Repositories' Click the button labelled 'New'.
- Name the repository and click 'Create repository'.
- Your new repository is now set up and ready to use.
-
Creating a forked repo creates a copy of a repo within github account.
How to Fork A Repository:
- Sign in to Github and go to the required repo.
- Locate the Fork button at the top right of the page.
- Click the button then click 'Create Fork'.
- You have now successfully forked the repo.
-
Cloning a repo creates a copy of a repo on your local machine.
How to Clone A Repository;
- Sign in to Github and go to the required repo.
- At the top of the page, above the files, is a button labelled 'Code'
- Select the required option from HTTPS, SSH or Github CLI, then click the clipboard icon to copy the URL.
- Open git bash
- Type 'git clone' and then paste the copied URL. Press Enter.
-
-
-
This project is built on the Django framework.
Django can be installed by following the steps below:
-
In your chosen IDE type the command:
pip3 install django -
To create an name your project use the command:
django-admin startproject <your_project_name> . -
A gitignore file is an important addition as you can specify which files should not be uploaded to the Github repo, such as database credentials.
A gitignore file can be created in the CLI using the command:
touch .gitignoreThe .gitignore file for this project can be found here
-
To check django has been installed and your project created successfully, type the following command:
python3 manage.py runserverFollowing the link provided in the CLI should display the Django landing page.
-
Next, initial database migrations need to be completed. This can be achieved with the command:
python3 manage.py migrateYou can see the changes to be made without executing them with the command:
python3 manage.py migrate --plan -
In order to have access to the admin panel, a superuser is required. This is created with the command:
python3 manage.py createsuperuserThis will then ask you to create a username and password with an optional email address.
-
Once these steps are completed you can push your changes to Github using the commands below in order, or with the interface in your chosen IDE:
git add . git commit -m "initial commit" git push
-
Heroku is the chosen cloud platform for the project, allowing the project to be built and deployed via a link to the Github Repo.
- Once you are logged in to Heroku, click the 'New' button in the top right corner of the page and select 'Create new app'.
- Select a name for your app (which must be unique!), select the closest region to you and click 'Create App'.
- Once the app has been created, select the resources tab, navigate to the 'Add-ons' section and search for 'Heroku Postgres'.
- Select 'Heroku Postgres', then under 'Plan name' choose 'Hobby Dev - Free' and click 'Submit Order Form'.
To use Postgres with Django, additional tools are required, and can be installed via the CLI in your chose IDE.
-
In your CLI type the command:
pip3 install dj_database_url -
Once completed, enter the following command into the CLI:
pip3 install psycopg2-binary -
At the top of the settings.py file in your main project folder, and the line:
import dj_database_url -
Scroll down in settings.py to the
DATABASESsection. Replace the code in this section with the code below.DATABASES = { 'default': dj_database_url.parse(<DATABASE_URL_GOES_HERE>) }The Postgres Database URL can be found in the settings tab of your app in Heroku, under the Config Vars section.
-
As we are now connected to a new database, we need to repeat the previous migration steps. This is done by running the command:
python3 manage.py migrate -
We also need to create a new superuser with the command :
python3 manage.py createsuperuser -
Before we commit these changes, we will need to alter the
DATABASESsection in settings.py to prevent the Postgres Database URL ending up in version control. -
This can be achieved by replacing the existing content of the
DATABASESsection with the code below.if 'DATABASE_URL' in os.environ: DATABASES = { 'default': dj_database_url.parse(os.environ.get('DATABASE_URL')) } else: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } -
Gunicorn needs to be installed next, which acts as our web server. This is done with the command:
pip3 install gunicorn -
We also need to create a
Procfileto tell Heroku to create a web dyno. In the root directory of your app, create a file namedProcfileand inside insert the code:web: gunicorn PROJECT_NAME_HERE.wsgi:application -
In Heroku, we need to prevent the collection of static files until we have set up AWS. This is achieved by navigating to the Settings tab in Heroku, selecting the Config_Vars section and entering
DISABLE_COLLECTSTATICin theKEYfield, and1in theVALUEfield and clicking the 'Add' button.When the site is deployed at this stage, no static files will be present, but this will be rectified later.
-
In order to allow your project to be viewed when deployed to Heroku, we need to add the Project URL to the
ALLOWED_HOSTSsection of settings.pyALLOWED_HOSTS = ['PROJECT_NAME_HERE.herokuapp.com', 'localhost', '127.0.0.1'] -
The changes can now be committed and pushed to Github. Once this has been done, we can push the changes to Heroku with the command:
`git push heroku main'
Amazon's AWS platform us used to store all static and media files.
- An AWS account is required which can be created here.
- Once you have created an account and logged in, select the
Servicesbutton in the top left corner of the page, scroll to the bottom and selectStoragefollowed byS3. - Once on the S3 page we can create a new bucket by clicking the orange
Create bucketbutton on the right side of the page. - Provide a name for the bucket and select the closest region to you.
- Under
Object OwnershipselectACLs enabledand leave the Object Ownership asBucket owner preferred. - Uncheck
Block all public accesscheckbox and check the warning box to acknowledge that the bucket will be made public, then clickCreate bucketat the bottom of the page. - Once created, click your bucket's name and navigate to the
Propertiestab. Scroll to the bottom and underStatic website hostingclick theEditbutton. Change theStatic website hostingoption toEnable. Typeindex.htmlinto theIndex documentfield. You can then scroll to the bottom of the page and clickSave Changes. - Navigate to the
Permissionstab, Scroll to theCross-origin resource sharing (CORS)section, click theEditbutton and paste in the following code:[ { "AllowedHeaders": [ "Authorization" ], "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "*" ], "ExposeHeaders": [] } ] - Scroll up to the
Bucket Policysection. Click theEditbutton and thenPolicy generator. - Select
S3 Bucket Policyin the 'Select Type of Policy' dropdown menu. Inside thePrincipalfield type\*to allow all principals. - Select
GetObjectfrom theActionsdropdown menu. - Head back to the previous tab and navigate to the
Propertiestab. Copy the value from theAmazon Resource Name (ARN)field, return to thePolicy Generatortab and paste the value into theAmazon Resource Name (ARN)field . - Once this has been completed, click
Add statement, thenGenerate Policy. Copy the generated policy and paste it into theBucket policyeditor. - Before saving, add a
/*at the end of your resource key. This is to allow access to all resources in this bucket. - Next, scroll down to the
Access control list (ACL)section and click theEditbutton. - Next to
Everyone (public access), check theListcheckbox. This will generate a warning which must be acknowledged. Once this is done clickSave changes.
- Now that the bucket has been created, we need to create a user to access it. In the search bar at the top of the page, type
IAMand select it. - Once on the
IAMpage, clickUser Groupsfrom the side bar on the left of the page, followed byCreate groupin the top right of the next page. - To make managing mulitple projects in the future a little easier, it's best to name your user group something like
manage-_your-project-name_. Once you've selected a name, clickCreate groupat the bottom of the page. - From the side bar on the left of the page, click
Policies, thenCreate policy. - Select the
JSONtab and clickImport managed policy. Search forS3and selectAmazonS3FullAccess. Click import. - Once imported this will need to be edited slightly. Return to your bucket and copy your ARN number. Back on the
Create polioypage, update the Resource key to include your ARN, and another line with your ARN followed by a/*. It should look like the code below:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:*", "s3-object-lambda:*" ], "Resource": [ "YOUR-ARN-HERE", "YOUR-ARN-HERE/*" ] } ] } - Click the
Next: Tagsbutton, click theNext: Reviewbutton. Enter your policy name into theNamefield andclickCreate policy. - Click on
User groupsin the side bar on the left of the page, and click the earlier created group. Go to thePermissionstab and clickAdd permissionand selectAttach policies. - Find the newly created policy, select it and click
Add permissions. - Finally, we need to create a user. Select
Usersfrom the side bar on the left of the page and clickAdd users. - Give your user name related to your project, such as
project-name-static-user, checkAccess key - Programmatic access, and clickNext: Permissions. - Select your previously created group with the required policy attached and click
Next: Tags,Next: Review, thenCreate user. - On the next page, download the CSV file. This contains the user's access key and secret access key which you will need later.
Now that AWS has been fully configured for our needs, we need to connect Django to AWS.
-
Firstly, we will need to install two packages.
Boto3anddjango-storages, which can be done with the following commands:pip3 install boto3 pip3 install django-storages -
Add
storagesto theINSTALLED_APPSsection of settings.py. -
We also need to add some additional settings to let Django know which AWS bucket it will be communicating with.
-
At the bottom of settings.py add the following code:
if 'USE_AWS' in os.environ: AWS_STORAGE_BUCKET_NAME = 'your-bucket-name-here' AWS_S3_REGION_NAME = 'insert-your-region-here' AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') -
We now need to return to Heroku. In the
Settingstab, underConfig Vars, we need to add the values from the CSV file we downloaded earlier. -
Add the key
AWS_ACCESS_KEY_IDwith the value that was generated in the CSV file. Add the keyAWS_SECRET_ACCESS_KEY, and add the value that was generated in the CSV file. Add the keyUSE_AWSand set the value to True. -
We can now also remove the DISABLE_COLLECTSTAIC variable, as we now want static files to be collected and uploaded to AWS.
-
Return to the settings.py file and add the following code to the
USE_AWSif statement created earlier:AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com' -
We need to create a file to tell Django that we want to use S3 to store our static files. In the root directory of your project, create a file called
custom_storages.py. Inside this file add the following code:from django.conf import settings from storages.backends.s3boto3 import S3Boto3Storage -
Underneath the imports insert these two classes:
class StaticStorage(S3Boto3Storage): location = settings.STATICFILES_LOCATION class MediaStorage(S3Boto3Storage): location = settings.MEDIAFILES_LOCATION -
In settings.py, underneath the bucket config settings but still inside the if statement, add these lines:
STATICFILES_STORAGE = 'custom_storages.StaticStorage' STATICFILES_LOCATION = 'static' DEFAULT_FILE_STORAGE = 'custom_storages.MediaStorage' MEDIAFILES_LOCATION = 'media' -
Next, you will also need to override and explicitly set the URLs for static and media files using your custom domain and new locations. To do this add these two lines inside the same if statement:
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{STATICFILES_LOCATION}/' MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/' -
We can now save, add, commit and push the changes and files will b e added to the AWS S3 bucket. Inside the if statement add the code below which lets the browser know it can cache static files:
AWS_S3_OBJECT_PARAMETERS = { 'Expires': 'Thu, 31 Dec 2099 20:00:00 GMT', 'CacheControl': 'max-age=94608000', }14.InS3onAWS, go to your project bucket and clickCreate folder. Name the foldermediaand clickSave. -
Inside the media folder, click
Upload,Add files, and then select all media files used in your project. -
Under
Permissions, selectGrant public-read accessand clickUpload. You will need to acknowledge the displayed warning before you can do this.
Stripe is used to handle the checkout process when a payment is made. A Stripe account is needed. You can sign up here.
- To set up Stripe payments you can follow the guide available here.
- To set up a webhook, sign into your Stripe account and click
Developerslocated in the top right of the navbar. - In the side bar on the left of the page, click
Webhooks, thenAdd endpointon the right side of the page. - Enter your Heroku project name, checkout app name, followed by wh into the
Endpoint URLfield. It should look something like this:https://your-app-name.herokuapp.com/checkout/wh/ - Click
+ Select eventsand checkSelect all eventsat the top of the page. ClickAdd eventsat the bottom of the page, followed byAdd endpointon the next page. - The webhook has now been created and should have generated a secret key. We will need this to add to the Heroku Config Vars.
- Open your app on Heroku and navigate to the
Config Varssection under theSettingstab. You will need the secret key just generated for your webhook, in addition to your Publishable key and secret key that you can find on the Stripe API keys page. - Add these values and key pairs to the Config Vars:
STRIPE_PUBLIC_KEY = 'insert your stripe publishable key' STRIPE_SECRET_KEY = 'insert your secret key' STRIPE_WH_SECRET = 'insert your webhooks secret key' - In setting.py in your Django project, insert the following near the bottom of the file:
STRIPE_PUBLIC_KEY = os.getenv('STRIPE_PUBLIC_KEY', '') STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY', '') STRIPE_WH_SECRET = os.getenv('STRIPE_WH_SECRET', '')
-
Delboy for the "Back to Top" idea in the readme.
-
-
All product images have been taken from the current website for Nibble Kitchen, with permission from the owner.
-
The main background image used on the 'Home' page was made available via Unsplash by the user Deva Williamson and is used under the Unsplash License.
-
The image used on the 'About Us' page was made available via Unsplash by the user American Heritage Chocolate and is used under the Unsplash License.
-
-
- AllAuth - Django app used for local authentication.
- Am I Responsive - Used to verify responsiveness of website on different devices.
- Balsamiq - Used to generate Wireframe images.
- Browser Stack - Used for Cross Site Browser Testing.
- Chrome Dev Tools - Used for overall development and tweaking, including testing responsiveness and performance.
- Django Crispy Forms - Django app to allow control over rendering behaviour of django forms.
- Django Quill Editor - WYSIWYG editor added for easy updating of text only content on the site.
- Favicon.io - Used to generate Favicon image.
- Flake8 - Linter used to check style and quality of code.
- Flake8 HTML - Tool to output Flake8 test report.
- Font Awesome - Used for icons on multiple pages.
- GitHub - Used for version control.
- Gunicorn - Python WSGI HTTP Server
- Heroku - Used for deployment and hosting of the project.
- JQuery - Used to simplify definition of DOM elements, but used minimally with a preference for vanilla Javascript.
- JSHint - Linter used to flag errors, bugs and warnings in Javascript code.
- Pillow - Python Imaging Library to add image processing capabilities to the project.
- Prettier - Used for consistent code formatting.
- Slack - Used for support and advice from the Code Insitute Community.
- Sorted M2M Filter Horizontal Widget - Django admin widget to allow horizontal sorting of products and ingredients.
- Stripe - Payment Processing Platform used to handle card details in the checkout app.
- Visual Studio Code - Application used for development of this site.
- W3C - Used for HTML & CSS Validation.
- WAVE - Used for Accessibility evaluation.
- Woosmap - Provided address searching API for checkout app.





















