Welcome to The Kicks Fix, your one stop destination for trainers, sneakers, gutties or kicks, as I like to call them. Navigate through the website and see if you can find the kicks that are meant for you from the wide selection available. After you find the perfect pair, like Cinderella at the Ball, why not choose some accessories or invest in some TLC - Trainers Loving Care products to maintain your purchase for as long as possible. So come have a look and don't forget to register for an account .... to take advantage of tailored discounts and promotions !!!
Unfortunately, this is my final project which means I will have finished my course and this saddens me to be honest but I know this is my springboard to a better future. I love coding and learning new things so for the last time, I am going to throw everything into this one and I hope you will all love it. I have combined my love for Djing, retro games and vinyls into my first three projects so all that is left is my love for KICKS. One of the first things my mentor ever said to me was design the website based on something that makes you happy which I have stuck to thus far. I have a serious Kicks Addiction, hence my project name, and cannot stop buying them ha ha, even if I never wear them which also drives me crazy. I hate the fact that they might get dirty but eventully I'll give in and wear them ..... the odd time and in dry weather too which means about two days a year in Ireland, lol.
And just so you know depending on your location around the world, you may have a different name for your athletic / casual footwear as mentioned above so for the purposes of this project I will be calling them KICKS ! I know that in the UK they are generally called Trainers and in America they are generally called Sneakers or if you're really oldskool, like 19th century oldskool, you may call them Gutties .... which is what I grew up calling them to be honest but this is because I'm Irish ha ha.
Sorry but I felt I had to clarify this before I continue, just to eliminate any confusion plus I feel KICKS is more universal and more down with the kids, nowadays !
Anyways, thank you for checking my final project out and I really hope you love the overall feel of my website :)
As a user I want to be able to register for an account so that I can have access to unique promotions and discounts
As a user I want to be able to login and logout with ease
As a user I want my own personal space after registering by means of a profile page
As a user I want to be able purchase any product I desire
As a user I want be able to search / filter the products by various options like male, female, kids, sizes, brands and so on
As a user I want to see my total spend as I continue my shopping spree within the site
As a user I want to be able to see all products with ease as I scroll down the items
As a user I want to be able to see individual products with one click and their various unique details like description, price, available sizes and so on
As a user I want to be able to create a wishlist of products for future purchasing
As a user I want to be able to add my payment details with ease and possibly store them safely, for future usage (only as a registered user obviously)
As a user I want confirmation of my order by an instant pop up and a follow up email
As a user I want to be able to contact the site owner, in case I have any issues or payment queries
As admin I want to be able to ADD products easily
As admin I want to be able to EDIT products and prices
As admin I want be able to DELETE products as and when required
As admin I want be able to add offers and promotions as and when required like Christmas or personal Birthday Treats for example.
I think for fonts I need to keep this fairly simple because my website is going to be available to all ages so I need the font to be really legible especially for kids. As per usual I have delved into my main source for fonts, the glorious Google Fonts. From the multitude of fonts I have settled on Lora for my titles / main headings and Poppins for my main content. I just love the combination of these two which is the most important factor but their names come a close second for me.
Below is an example of my fonts where the title is in Lora and the text is in Poppins .....
Font Awesome will be the main source for any icons that I require. I will deffo be using the various basic icons and some shopping based icons on my website. Other than that, we will just have to see what suits and fits the web page layout perfectly.
I have used the Coolors website to come up with my colour scheme for this project and I love this wee website, as it has amazing combinations already there for developers to utilise them. As always though, I want to go for fairly bright colours as I want my website to be lively and standout but not too bright that it will hurt thy old eyes. I deffo do not want boring colours that smell of depression or prison either ! Therefore, I went for the typical white and black but versions that are just slightly off colour. I also settled on a red and a yellow to brighten up the overall feel as mentioned above.
Below is an image of the chosen colours .....
So a better breakdown of the colours are shown below:
Name | Hex Code | Basic Description | Usage |
---|---|---|---|
Cultured | #F5F5F5 | Off White | Body background, text & titles |
Minion Yellow | #FEE440 | Bright Yellow | Body background |
Imperial Red | #E63746 | Brightish Red | Body background |
Eerie Black | #121416 | Off Black | Body background, text & titles |
The software that I used for my wireframes was Balsamiq. This was the fourth time I used this software and I really enjoy designing my project layouts using this. The software allows you design the basic layout of your website on devices such as a desktop, tablet and mobile. They are just simple 2D sketches but I now understand how important these really are :) I think my wireframes look good and deffo give me a great starting point for the design process !
Anyway, you can have a wee look at my wireframes below:
For my database structure I had to think about this for a long time before I started my project. To be honest it took me while to get my head around it but I think I got there. After watching the Code Institute tutorials again, endless Youtube videos and undeniable assistance from my lengendary mentor, I have produced my first Database Schema. I didn't lay one out for my MS3 which cost me valuable marks but for this project, I wasn't going to make the same mistake. The Kicks Fix Schema is shown below where I have set up 15 models and have shown the various relationships between them. I may add more if required as my project develops and I think of new features that can be implemented but these are the main models that my project needs and I am very happy with the structure. I used drawSQL to construct my schema which is a free online app and really awesome, once you get the hang of it !
During the development, I worked with sqlite3 databases, installed with Django. For production, I've used a PostgreSQL database which is provided in Heroku as an add-on.
django.contrib.auth.models
. Name | Database Key | Field Type | Validation |
---|---|---|---|
User | user | OneToOneField 'User' | on_delete=models.CASCADE |
Phone Number | default_phone_number | models.CharField | max_length=20, null=True, blank=True |
Street Address 1 | default_street_address1 | models.CharField | max_length=80, null=True, blank=True |
Street Address 2 | default_street_address2 | models.CharField | max_length=80, null=True, blank=True |
Town or City | default_town_or_city | models.CharField | max_length=40, null=True, blank=True |
County | default_county | models.CharField | max_length=80, null=True, blank=True |
Postcode | default_postcode | models.CharField | max_length=20, null=True, blank=True |
Country | default_country | CountryField | blank_label='Country', null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254, default='home' |
Main Slogan | main_slogan | models.CharField | max_length=254 |
Promotional Bar | promotion_bar | models.CharField | max_length=254 |
Social Icon | social_icon | models.ForeignKey 'Social' | null=True, blank=True, on_delete=models.SET_NULL |
Discount Code | discount_code | models.ForeignKey 'Discount' | null=True, blank=True, on_delete=models.SET_NULL |
Main Logo URL | main_logo_url | models.URLField | max_length=1024, null=True, blank=True |
Main Logo | main_logo | models.ImageField | null=True, blank=True |
Toast Logo URL | toast_logo_url | models.URLField | max_length=1024, null=True, blank=True |
Toast Logo | toast_logo | models.ImageField | null=True, blank=True |
Loader Logo URL | loader_logo_url | models.URLField | max_length=1024, null=True, blank=True |
Loader Logo | loader_logo | models.ImageField | null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254 |
Friendly Name | friendly_name | models.CharField | max_length=254, null=True, blank=True |
Image URL | image_url | models.URLField | max_length=1024, null=True, blank=True |
Image | image | models.ImageField | null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254, default='discount' |
Discount Code | discount_code | models.CharField | max_length=25 |
Discount Percentage | discount_percentage | models.DecimalField | max_digits=2, decimal_places=0, default=0 |
Free Delivery Threshold | free_delivery_threshold | models.DecimalField | max_digits=2, decimal_places=0, default=0 |
Standard Delivery Percentage | standard_delivery_percentage | models.DecimalField | max_digits=2, decimal_places=0, default=0 |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254 |
Friendly Name | friendly_name | models.CharField | max_length=254, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=50 |
Friendly Name | friendly_name | models.CharField | max_length=50, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=50, , default='size' |
Friendly Name | friendly_name | models.CharField | max_length=50, null=True, blank=True |
Size | size | models.JSONField | default=list |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=50 |
Friendly Name | friendly_name | models.CharField | max_length=50, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Category | category | models.ForeignKey 'common.Category' | null=True, blank=True, on_delete=models.SET_NULL |
Sex | sex | models.ForeignKey 'common.Sex' | null=True, blank=True, on_delete=models.SET_NULL |
SKU | sku | models.CharField | max_length=254 |
Brand | brand | models.ForeignKey 'Brand' | null=True, blank=True, on_delete=models.SET_NULL |
Name | name | models.CharField | max_length=254 |
Style | style | models.ForeignKey 'Style' | null=True, blank=True, on_delete=models.SET_NULL |
Description | description | models.TextField | |
Price | price | models.DecimalField | max_digits=6, decimal_places=2, default=0.00 |
Colour | colour | models.ForeignKey 'common.Colour' | null=True, blank=True, on_delete=models.SET_NULL |
Image1 URL | image1_url | models.URLField | max_length=1024, null=True, blank=True |
Image1 | image1 | models.ImageField | null=True, blank=True |
Image2 URL | image2_url | models.URLField | max_length=1024, null=True, blank=True |
Image2 | image2 | models.ImageField | null=True, blank=True |
Image3 URL | image3_url | models.URLField | max_length=1024, null=True, blank=True |
Image3 | image3 | models.ImageField | null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254 |
Friendly Name | friendly_name | models.CharField | max_length=254, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254 |
Friendly Name | friendly_name | models.CharField | max_length=254, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Category | category | models.ForeignKey 'common.Category' | null=True, blank=True, on_delete=models.SET_NULL |
SKU | sku | models.CharField | max_length=254 |
Name | name | models.CharField | max_length=254 |
Type | type | models.ForeignKey 'Type' | null=True, blank=True, on_delete=models.SET_NULL |
Description | description | models.TextField | |
Price | price | models.DecimalField | max_digits=6, decimal_places=2, default=0.00 |
Colour | colour | models.ForeignKey 'common.Colour' | null=True, blank=True, on_delete=models.SET_NULL |
Image1 URL | image1_url | models.URLField | max_length=1024, null=True, blank=True |
Image1 | image1 | models.ImageField | null=True, blank=True |
Image2 URL | image2_url | models.URLField | max_length=1024, null=True, blank=True |
Image2 | image2 | models.ImageField | null=True, blank=True |
Image3 URL | image3_url | models.URLField | max_length=1024, null=True, blank=True |
Image3 | image3 | models.ImageField | null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Name | name | models.CharField | max_length=254 |
Friendly Name | friendly_name | models.CharField | max_length=254, null=True, blank=True |
Name | Database Key | Field Type | Validation |
---|---|---|---|
Order Number | order_number | models.CharField | max_length=32, null=False, editable=False |
User Profile | user_profile | models.ForeignKey 'UserProfile' | on_delete=models.SET_NULL, null=True, blank=True, related_name='orders' |
Full Name | full_name | models.CharField | max_length=50, null=False, blank=False |
models.EmailField | max_length=254, null=False, blank=True | ||
Phone Number | phone_number | models.CharField | max_length=20, null=False, blank=False |
Country | country | CountryField | blank_label='Country *', null=False, blank=False |
Postcode | postcode | models.CharField | max_length=20, null=True, blank=True |
Town or City | town_or_city | models.CharField | max_length=40, null=False, blank=False |
Street Address 1 | street_address1 | models.CharField | max_length=80, null=False, blank=False |
Street Address 2 | street_address2 | models.CharField | max_length=80, null=True, blank=True |
County | county | models.CharField | max_length=80, null=True, blank=True |
Date | date | models.DateTimeField | auto_now_add=True |
Delivery Cost | delivery_cost | models.DecimalField | max_digits=6, decimal_places=2, null=False, default=0 |
Order Total | order_total | models.DecimalField | max_digits=10, decimal_places=2, null=False, default=0 |
Grand Total | grand_total | models.DecimalField | max_digits=10, decimal_places=2, null=False, default=0 |
Original Bag | original_bag | models.TextField | null=False, blank=False, default='' |
Stripe PID | stripe_pid | models.CharField | max_length=254, null=False, blank=False, default='' |
I struggled a little at the start with this but the more I got into the project I started to understand most of it and how it all worked. Don't get me wrong, I still have a lot to learn which will come when the pressure to meet the project deadline is off and I can test Django out at my own pace. I never got to utilise my Wishlist for the user to have their own personal wishlists or Social for ALL the social icons that I was going to link but I'll just add these to Features to be Implemented. I did try my best to add as much to the backend as possible like the logos, delivery costs, delivery threshold etc so that if any changes needed to be made for these, it would be much simplier.
The more I play around and practise with Django and databases then the more confident and experienced I'll become, which is only a good thing, but while I had many head scratching evenings after work, I think the overall structure is okay and far from perfect but it works and that's the main aim here.
Testing can be found on here in a seperate file
Bugs can be found on here in a seperate file
I have created this project using Github, from there I used Gitpod to write my code, as I have for ALL four projects now. Then I used commits to git followed by "git push" to my GitHub repository. I've deployed this project to Heroku and used "git push heroku main" to make sure my pushes to GitHub were also made to Heroku.
For this project you need to create an account on Stripe for the Checkout App, as well as an account on AWS in order to store your static and media files.
This project can be ran locally by following the following steps:
I used Gitpod for development, so the following steps will be specific to Gitpod.
You will need to adjust them depending on your IDE. You can find more information about installing packages using pip and virtual environments here
To clone the project:
From the application's repository, click the "code" button and download the zip of the repository. Alternatively, you can clone the repository using the following line in your terminal:
git clone https://github.com/RaVeR76/The-Kicks-Fix.git
Access the folder in your terminal window and install the application's link to required modules using the following command:
pip3 install -r requirements.txt
In your IDE, create a file containing your environmental variables called env.py at the root level of the application. It will need to contain the following lines and variables:
import os
os.environ["SECRET_KEY"] = "YOUR_SECRET_KEY"
os.environ["DEVELOPMENT"] = "True"
os.environ["DEFAULT_FROM_EMAIL"] = 'DEFAULT_FROM_EMAIL'
os.environ["STRIPE_PUBLIC_KEY"] = "STRIPE_PUBLIC_KEY"
os.environ["STRIPE_SECRET_KEY"] = "STRIPE_SECRET_KEY"
os.environ["STRIPE_WH_SECRET"] = "STRIPE_WH_SECRET"
os.environ["STRIPE_CURRENCY"] = "GPB"
If you're not sure how to get the above Stripe variables, please visit the Stripe Documentation
If you plan on pushing this application to a public repository, ensure that env.py is added to your .gitignore file.
Migrate the database models with the following command
python3 manage.py migrate
Create a superuser and set up the credentials with the following command
python3 manage.py createsuperuser
Run the app with the following command
python manage.py runserver
The address to access the website is displayed in the terminal
Add /admin to the end to access the Django Admin panel with your superuser credentials
Login to your Heroku account and create a new app (best calling it the same or something similar to your project name). Choose your region.
Once the app is created click on the resources button and under Add-ons, look for the Heroku Postgres to attach a postgres database to your project. Select the Hobby Dev - Free plan and click 'Submit order form'
Scroll back up and click "settings". Scroll down and click "Reveal config vars". Set up the same variables as in your env.py
.
You shouldn't set the DEBUG variable in under config vars, only in your env.py
to prevent DEBUG being active on live website.
AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"
AWS_SECRET_ACCESS_KEY = "AWS_SECRET_ACCESS_KEY"
AWS_S3_REGION_NAME = "AWS_S3_REGION_NAME"
AWS_STORAGE_BUCKET_NAME = "AWS_STORAGE_BUCKET_NAME"
USE_AWS = True
DATABASE_URL = "This variable is automatically set when adding the Postgres Add on"
SECRET_KEY = "SECRET_KEY"
STRIPE_PUBLIC_KEY = "STRIPE_PUBLIC_KEY"
STRIPE_SECRET_KEY = "STRIPE_SECRET_KEY"
STRIPE_WH_SECRET = "STRIPE_WH_SECRET"
STRIPE_CURRENCY = GPB
DEFAULT_FROM_EMAIL = "DEFAULT_FROM_EMAIL"
EMAIL_HOST = "smtp.gmail.com"
EMAIL_HOST_PASS = "EMAIL_HOST_PASS"
EMAIL_HOST_USER = "EMAIL_HOST_USER"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
Make sure your manage.py file is connected to your mysql database like below
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
Use this command to backup your current database and load it into a db.json file:
python3 manage.py dumpdata --exclude auth.permission --exclude contenttypes > db.json
From your Heroku Config Vars, copy the value of DATABASE_URL
After this go to your settings.py in the the_kicks_fix directory and comment out the default database configuration shown above and add:
DATABASES = {
'default': dj_database_url.parse('Put your DATABASE_URL here'))
}
Migrate again with the following command
python3 manage.py migrate
Create a superuser for the postgres database so you can have access to the django admin by setting up the credentials with the following command
python3 manage.py createsuperuser
Don't forget to login to the admin page and check the boxes 'Verified and Primary"
Load the data into your newly created database by using the following command:
python3 manage.py loaddata db.json
After migrations are complete, change database configurations to:
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',
}
}
This set up will allow your site to use Postgres in deployment and sqlite3 in development.
Make sure you have your requirements.txt file and your Procfile. In case you don't, follow the below steps: Requirements:
pip3 freeze --local > requirements.txt
Procfile:
echo web: python app.py > Procfile
The Procfile should contain the following line:
web: gunicorn <project_name>.wsgi:application
Add your files and commit them to GITHUB by running the following commands:
git add .
git commit -m "Your commit message"
git push
Add your Heroku app URL to ALLOWED_HOSTS in your settings.py file
Disable collect static so that Heroku doesn't try to collect static files when you deploy by typing the following command in the terminal
heroku config:set DISABLE_COLLECTSTATIC=1
Go back to HEROKU and click "Deploy" in the navigation.
Scroll down to Deployment method and Select Github.
Look for your repository and click connect.
Under automatic deploys, click 'Enable automatic deploys'
Just beneath, click "Deploy branch". Heroku will now start building the app. When the build is complete, click "view app" to open it.
In order to commit your changes to the branch, use git push to push your changes.
Store your static files and media files on AWS. You can find more information about this on Amazon S3 Documentation.
Set up email service to send confirmation email and user verification email to the users. You can do this by following the next steps (Gmail only)
(Be aware that this migth be different for other providers or the process might have changed over time)
EMAIL_HOST_PASS = 'Password you just copied'
EMAIL_HOST_USER = 'Your gmail account
if "DEVELOPMENT" in os.environ:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL')
else:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASS')
DEFAULT_FROM_EMAIL = os.environ.get('EMAIL_HOST_USER')
The Kicks Fix is now deployed on Heroku with AWS storing media files and static files ..... ENJOY !!!
So the end is nigh ! .... and this is basically the last part of my project to do as I have completed everything else so I'll keep it short.
At the start of this project, I spent a lot of time getting the images right and then I had to scroll through the internet for decriptions, SKUs, estimated prices etc etc. This took so much time to sort out which I didn't realise and deffo had a knock on effect by not getting everything I wanted within my website completed. Whilst some of the images aren't the best looking and the descriptions are so random, they are the best I could find, especially for the Accessories. It was hard work and very monotonous looking for all the info for the images that I had downloaded from Kaggle. The file was 8.46 Gb of kick images which I trawled through for the best sets I could. I had another folder from Kaggle which was only 383 Mb but there was only one image of each Kicks here and I really wanted the three for my wee carousel. Also spending all that time cutting, editing and resizing them all to 400x400 pixels deffo made the overall display look more universal with no odd shaped images throwing it all off tilt.
There are a lot more Adidas Kicks than any other, a lot more Lifestyle styles than any other and prices may not just be right but you need to look past this at this point, as it's mainly about the code but I still don't want you to forget the effort in getting the data ha ha .... holy moly, there are even a pair of Green Puma Rihanna sandals threw in there for good measure ha ha !!!
In the real world, this would be a job for another colleague to get these pics / images ready for the site so during this project not only was I the developer but also the graphic designer too ha ha. I even made the wee logo to go with it all.
Just so you know how much effort I put into this project too, I have added PDF versions of my my Excel Spreadsheet that I kept a log of everything on, as I went along.
There was my diary, my bugs, my Django model data, all my Kicks data and all my Accessory data that I gathered online .... all on one wee spreadsheet. Please check the various sections out below if you want:
At the end of the day, I have fully put my heart and soul into this project and sat for a month and a half every week night and ALL weekend EVERY weekend, trying to do the best that I could. Like I said whilst I didn't get some things completed that I wanted, like my Wishlist function, I am still so so happy with the overall look and functionality of my website. It actually looks like a proper E-Commerce WEBSITE !!!
Anyway, as sad as it is, that this is my last Project on the course, and it is sad ... believe me, but I cannot believe how far I have came in a year. A year ago I didn't even know what HTML stood for, I still don't ha ha, only messing but what I have learned, the friends I have gained in the Slack community, my mentor who I adore and basically the whole Coding Community (such a clever bunch of people) .... I personally would not have gotten this far without YOU ALL !!!!
So thank you to anyone who is reading this and if you helped me along the way (high five peeps) .... I really hope you enjoy this project because it's accumulated from a year of high, lows, tears, laughter, imposter syndrome, hating JavaScript then loving JavaScript, pesking extra commas, effort, hard work, dedication and so on ... you all know the score because you've all been there.
Anyways, I'm off to watch TV because I haven't seen one for the last month and a half ha ha but listen ... deep down, I REALLY hope you enjoy ........ THE KICKS FIX !!!
Code Credits
This project was developed by following Code Institute course material for 'Boutique Ado Django Mini-Project' - Without this I would have been LOST !!!
Dropdown within a dropdown but made it my own - Dropdown Submenu
Card hover code but adjusted it for my site
Payment Loader but edited for my site
Django documentation
Bootstrap 4.6 documentation
Stripe documentation
Image Credits
All Kicks images taken from this humongous set, only 9.32Gb of images, at Kaggle
Hero Image from Pexels, by CrimsonPeak and edited for my site
The Kicks Fix logo - designed by me
Other Credits
Special Shout Outs
Firstly to my testers - my family, my work colleagues and of course Wee Ro ... who always believed in me, even when I gurned about it !
My 'patient' mentor Simen Daehlin, for helping me develop my coding skills by giving awesome advice and direction :)
Code Institute and Tutor Support - Amazing people and Coding GODS who I needed to summon a few times during this project !
Slack for continuous information, help links, tutorials, laughter, support .... I could go on
Stackoverflow, useful resource site for finding solutions to many issues I had
This site is mainly for educational purposes only and to be honest ..... The prices are extortionate here ha ha !!!