The Unconventional Programmer is a blog/Reddit style website targeted at aspiring and junior developers. This site aims to share useful resources that will help people who have taken unconventional routes into programming and are at the start of their careers. It is a site that allows users to share their personal experiences via either creating a blog post themselves or commenting on existing ones.
The website was built in Django using Python, JavaScript, CSS and HTML. Users are can create, edit, read and delete posts. On login, a profile is automatically created for them which users can click into and edit/update. They can upload images for their blogs as well as a profile picture. Users can also comment on and like/unlike posts.
The site provides role-based permissions for users to interact with the central dataset. Included is user authentication and Full CRUD functionality for blog posts.
- User Experience (UX)
- Design
- Agile
- Database Schema
- Features
- Future Development
- Testing
- Solved Bugs
- Known Bugs
- Technologies Used
- Deployment
- Credits
- To provide users who are just starting out their careers in programming to find helpful resources
- To provide users with a place to share their knowledge and experiences
- To provide users with a place where they can feel part of a community of like-minded individuals
- To show users that they are not on their own and there are many people in the same shoes as them and feeling like them
- To show users that it gets better and that coding is a fantastic career choice
Sites Ideal Users
- Career changers currently studying at a coding Bootcamp
- Junior developers who are right at the beginning of their work journey
- Graduates with programming related degrees
- People looking to share their experience and knowledge with those less experienced
6 Epics were created which were further developed into 20 User Stories. The details of each epic along with the associated user stories can be found in the kanban board here.
- Initial Django Setup #1
- User Profile #5
- Sign in/Sign Out #12
- Blog Post #17
- Site Owner Goals #24
- Site Search #15
20 User stories were created from the 6 Epics and assigned the classifications of Must-have, Should-have, Could-have and Won't have. Each user story also includes acceptance criteria and tasks that need to be completed for that story to be closed.
Below are links to each of the individual user stories that were completed within the project's initial release.
-
Initial Django Setup
-
User Profile
-
Sign in/Sign Out
-
Blog Post
-
Site Owner Goals
- Responsive templates #26
For ease of reading, I have also listed all the completed user stories below:
- As a developer, I can set up Django and install all the supporting libraries to get started with the project, so that I am ready to start development
- As a developer, I can set up the Django development environment to secure the secrete keys, so that I do not expose the secret keys to the public or a party that should not see them
- As a developer, I can deploy the site to Heroku, so that I can confirm that everything is working before the development of the site and enable continuous testing with the production environment
- As a user, I can create an account by registering my details so that I can comment and like posts
- As a user, I can see the details of my user profile so that I can see my info and what others can see about me
- As a user, I can edit my profile so that I can keep my information up to date
- As a user, I can sign in and sign out of my account so that I can keep my account secure and private
- As a site owner I will restrict some features of the site to registered users only so that it encourages users to create an account with the site
- As a user, I can create a blog post so that I can share my ideas and experience
- As a user,I can read the blogs on the site so that I can benefit from the information shared
- As a user, I can update a blog I have created so that I can correct mistakes I've made
- As a user, I can delete a blog post I have written so that I can remove it from the site
- As a user, I can like or unlike blog posts so that valuable blog posts are recognised as good content
- As a user, I can comment on blogs so that I can have a community discussion around the topic and gain further insights
- As a site owner I can create my site to be fully responsive so that it provides a good user experience on all devices
Before coding commenced, a set of wireframes were created to help me visualise roughly what the website would look like on desktop, tablet and mobile. It provided a starting point in terms of design. The finalised project went through many iterations and has changed from the initial wireframes however, inspiration was taken from these wireframes.
- The colour scheme has been carefully chosen to ensure accessibility for all
- The colours compliment each other and ensure the text is easily read
- The colours are consistent throughout the website and are used for specific purposes
- The main colours used throughout the website are:
Other colours used also were #8C6D89(light purple), #fff (white) and #ED91B3 (light pink). The colour #ED91B3 replaced #ED5393 as the colour for the CTA buttons. This change was made for accessibility reasons and to ensure the colour contrast was within the correct ratio for readability.
The font used in this project was Roboto with a backup of sans-serif. It was chosen for its easy readability for users. Fonts were imported using Google Fonts.
Throughout this project, an agile approach was taken to developing the website. Each activity was broken down into smaller bite-sized more manageable actions from initially creating 6 Epics, which were then broken down into smaller User stories. Each of the user stories then had an acceptance criterion and a list of tasks to complete. This made the overall project much more manageable to build. GitHub labels were used to categorise the User Stories using the MoSCoW Prioritisation technique. This clearly defined what tasks were most important to complete and where the focus should be.
As mentioned above, a kanban board was created using GitHub Projects here to help keep track of all the tasks including Todo, In Progress, Done and Future Development.
Smart Draw was used to create a database schema to visualise the types of custom models this project might require. This schema was used as a guide to what needed to be added to each model. In the end only the Blog Post, Comment and Profile models were used due to time constraint. AllAuth was also used for the authentication system. This uses the built-in Django User Model.
A simplistic homepage with minimal distractions ensuring the users main focus is on looking through the blog post lists. The blog posts on the homepage are displayed in a single list view and provide a summary of what the blog contains. This provides the user with some quick information to see if they would like to find out more information about it including who submitted it when it was published, the topic of the post, a summary and how many likes it has received. These fields have all been included to provide the user with a better experience and be able to make an informed decision as to whether they would like to continue into the blog post to read it. Users do not need to be registered to view a post.
The navigation bar is featured on all pages, is responsive and has active links functionality so the user knows which link they are on by hovering on it in the navbar. It is identical on all pages and is easy to use providing a good user experience. For mobile view, the navbar reduces to a burger menu. The purpose of this feature is to allow users to navigate all pages easily across all devices without having to use a back button to get to the next page. There is also authentication in place which will change what displays on the navbar depending on whether a user is logged in or not.
- Logged out Navbar
- Logged in Navbar
The footer section includes links to relevant social links which all open up in a new tab to allow easy navigation for the user. They also have a hover effect added to them to make them stand out more and obvious to click. The copyright section is in place for legal reasons and the date is automatically updated using JavaScript. The footer is a good way to encourage users to connect via social media.
The blog posts have had pagination functionality added to them so that 3 posts are displayed on each page. This has been implemented to improve the user experience and not overwhelm the user with information and blog posts.
Each post has a title followed by a submitted by field. There are also Edit and Delete buttons for signed in users, which have been put at the top of the page to ensure the user doesn't miss them. The main content is then added using the WYSIWYG editor Summernote which provides basic styling and image uploads. At the bottom of the blog post, there is a section for users to leave comments and talk to each other as well as a like/unlike option. The purpose of the blog layout is to make it as easy as possible for a user to read the content, digest it and then contribute to it in the form of comments and likes.
Each blog post has a comment section where users can post their comments for that specific blog. The user can see the number of comments that have been made on the post, the name of the user who wrote each comment and when that comment was published. Users can only make a comment when signed in and will be prompted to sign-in or sign-up in order to leave comments. This is a great way for users to interact with each other and the publisher, discuss the topic and ask/answer questions.
- Not signed into an account
- Signed into account
The user can also like and unlike blog posts. The purpose of this is to provide useful feedback to the community on how popular/good a post is by rewarding that post with likes. If a user changes their mind they can remove their like from a post. Each like is counted on the blog page as well as on the homepage where the blog list sits. If a post is unliked by a user this is reflected in the count.
- Like
- Unlike
Django Allauth was installed and used to create the register, sign-in and sign-out functionality meaning the project would have the authentication foundations in place to expand functionality in future. These pages are needed to provide authenication and to allow users access to content that is restricted to those who have created a login.
- Login
- Logout
- Sign-up
If the user is logged in they can create a post. Current fields being captured include title, title tag, summary (which is used to display on the homepage), body (using the summernote editor) and topic.
If the user is logged in they can edit a post they have created but not anyone else. Same fields are included as with create a post.
Once a user has created a post they can delete their post. They can do this by accessing the blog that they have created and wish to delete and clicking the delete button at the top of the page. They will then be taken to a page asking them if they are sure they wish to delete their blog and to click confirm or go back to their blog page.
Once a user registers, they will have a profile page automatically created for them. The link to their profile page will appear in the navigation bar once logged in. If they navigate to this page, they will be able to update their username, email address, add a bio and upload an image. The purpose of this page is to provide users with more control over their account and start to be able to customise their data.
To provide users with more feedback after they take certain actions, a messaging system has been added to let users know their desired actions have occurred. For example:
- Login
- Logout
- Profile Updated
These messages last for 2 seconds before automatically being timed out. Alternatively, the user can click a little 'X' to remove them.
A superuser was created for this project to manage the backend admin section. Users with admin access have more functionality than normal users such as the ability to create, read, update and delete information like users, posts, profiles and comments.
Access is restricted to approved admins only and can be accessed by adding '/admin' to the URL on the homepage and signing in if not already signed in through the front end of the site.
There is much functionality that can be added to this project in the future including:
-
Blog search - a search box could be included on the homepage to allow users to search the site for posts by topic, author etc
-
Dark Mode Customisation - adding the ability to view the site in dark mode as this is a preferred method for a developer to work with code and would be a nice add on
-
Creating the functionality for users to be able to delete their account through their profile page and not just through the admin
-
Allowing users to reset/change their passwords
-
Report abusive/inappropriate comments flag - this would alert an staff member/admin user to then manually review a comment and be able to remove it if deemed abusive/inappropriate
-
Add comment nesting so that users can see specific responses to their comments
-
The ability for users to login via social networks such as Google or Facebook
Throughout development, errors and warnings were fixed as I went on such as indentation problems, syntax errors and missing code errors. I also went through all my code files once the main functionality and style of the website was completed by using validators and following best practice to eliminate problems with lines too long, trailing white spaces, stray divs etc.
Google Chrome developer tools were used to inspect pages and look through code to help debug errors caused by HTML, CSS or JavaScript code.
Manual and automated testing has been carried out, as well as proofreading of the ReadMe file using Grammarly.
I have manually tested all the features of the website making sure to go through them with different browsers and device sizes. I have also checked the features of the site against the original user stories to ensure they have all been actioned.
User Stories
Features
I have performed some basic automated tests on the forms, views and models as shown below.
- All the above tests passed as shown below
- I have also installed Coverage with pip3 install coverage and ran the program in the terminal using the coverage run manage.py test command. A file was generated with coverage html and the results can be found in the htmlcov folder in the index.html file.
Browsers
- The website was tested on the following browsers: Google Chrome, Firefox, Microsoft Edge and Safari.
- For each browser, functionality was tested including links and the responsive design.
- The website performed as intended and the responsive design was checked using developer tools across multiple devices with structural integrity holding for the various sizes.
Devices Tested
The website was viewed on a variety of devices of all sizes including:
- Windows 11 Desktop (screen resolutions tested in 2560x1080 and 1920x1080)
- MacBook Pro (13-inch 2015 version)
- Moto G4
- Galaxy S5
- Pixel 2
- Pixel 2 XL
- iPhone 5/SE
- iPhone 6/7/8
- iPhone 6/7/8 Plus
- iPhone X
- iPad
- iPad Pro
- Surface Duo
The official W3C Markup Validator was used to validate both the HTML and CSS of the project to ensure there were no syntax errors within the site.
W3C HTML Markup Validator
The below screenshots show the error messages that were found during the HTML page validation process. All errors have been fixed and none remain on any of the HTML pages.
Link to commit for fix
Link to commit for fix
Link to commit for fix
All passed pages:
W3C CSS Markup Validatior - https://jigsaw.w3.org/css-validator/validator
The JavaScript code was checked using jshint.com and returned no errors.
All python files that I created were run through the PEP8 linter to validate such as models.py, views.py, forms.py etc and any errors picked up were fixed. There are no errors left in these files.
Models.py File Example
- Errors in Models.py files
- All Models.py file errors fixed
Colour contrast checks have been made on the site using the Colour Contrast Accessibility Validator by a11y. All pages passed the colour contrast analysis except for the CTA button element on each page. The pink button with the white text didn't allow for a great enough contrast. Therefore, I decided to change the button colour to a less bright pink (#ED91B3) and the text colour to black. This increased the contrast and ensured maximum accessibility making the contrast ratio within an acceptable range.
The results are shown below:
Lighthouse was used to test the Performance, Best Practices, Accessibility and SEO for desktop and mobile. The results are all within acceptable ranges.
Desktop Results
Mobile Results
-
Users were able to submit forms with no body content. The validation needed to be added to the post model within the body field to let it know it was required. To do this I changed the fields blank and null to False which solved the problem. Link to commit
-
Summernote WYSIWYG editor wasn't responsive. To solve this I added additional config vars to change the width to 100%. Link to commit
-
New users who signed-up weren't having a profile created for them automatically so when clicking on the profile page on the navigation a RelatedObjectDoesNotExist error appeared. This was fixed by moving the code in the signals.py file directly into the model for the profile. Link to commit
-
Integrity error with duplicated keys. This was solved by making changes to the post model, urls and home.html template so that slugs would be read properly. Link to commit
There are no known bugs left in this project. If you find any please get in touch with me.
- Heroku - this was the platform used to deploy the application
- Django - Python framework used to create backend logic
- Bootstrap 5 - CSS framework used to develop responsiveness and mobile-first approach
- Django-allauth - authentication library used to create user accounts
- Gitpod - this was my code editor for this project
- Git - was used for version control using the terminal through Gitpod to commit to Git and push to Github
- Github - is used to store the code for this project after being pushed from Git
- Techsini - was used to generate multi-device website mockups
- Fireshot - this was a Google Chrome extension used to take screenshots
- PEP8 Online - was used to validate python code to ensure no errors were present
- Google Fonts - used to import fonts to website
- Font Awesome - library of icons used for social media and services we offer
- Balsamiq - was used to create the wireframes during the design process.
- GoogleDev Tools - was used to help investigate issues with code and visually see what code was related to which area on the page
- ColorSpace - used to generate colour pallets for use on website
- a11y - used to check website colour contrast and accessibility
- smartdraw - used to create the database schema
- Raw Pixel - used to find royalty-free images
- Favicon.io - generated the websites favicon
- SQLite: local database used to test during development
- PostgreSQL: database used in Heroku to store data on deployment
This application has been deployed using Heroku by following these steps:
- Commit all changes and push them to GitHub
- Log in to Heroku or create a new account
- From the Heroku dashboard click the "Create New App" button
- Enter the name of your app and the region you're located in. Then click "Create App". It is worth noting that your app name must be unique for Heroku to accept it
- In your app go to the Resources tab and add a Heroku Postgres database. This can be done by searching for Postgres in the Add-ons search box, select Heroku Postgres and choose the HobbyDev - Free option and submit
- Click on the "Settings" tab and scroll down to reveal config vars
- This will provide the Postgres Database URL, click on the url box and copy it
- Navigate over to your code, create a new file in the same directory as your manage.py file and name it env.py (this will be used to store secret environment variable whilst in development)
- Within this file import os library, and set the environment variable for the DATABASE_URL pasting in the address copied from Heroku. The line should appear as os.environ["DATABASE_URL"]= "YOUR Postgres Database URL from Heroku"
- Below DATABASE_URL add the secret key using os.environ["SECRET_KEY"] = "your secret key goes here"
- Add the secret key just created to the Heroku Config Vars as SECRET_KEY for the KEY value and the secret key value you created as the VALUE
- Navigate back to your code and go to your settings.py file and import Path from pathlib, import os and import dj_database_url (near the top of your settings page)
- Insert the line - if os.path.isfile("env.py"): import env
- Move down to the secret key section in the settings.py file, remove the insecure key and replace it with SECRET_KEY = os.environ.get('SECRET_KEY')
- Scroll down further and wire up Postgres database by replacing the databases section with DATABASES = { 'default': dj_database_url.parse(os.environ.get("DATABASE_URL"))} ensure the correct indentation for python is used.
- In the terminal migrate the models over to the new database connection
- In a browser, search for Cloudinary and either login or create an account and login
- Navigate to the Cloudinary dashboard and copy the CLOUDINARY_URL by clicking the copy to clipboard link
- Go back to your code and in the env.py file add a line at the bottom - os.environ["CLOUDINARY_URL"] = "paste in the Url copied to the clipboard here"
- In Heroku, go to settings and add the CLOUDINARY_URL and value copied to the clipboard to the config vars
- Also add in DISABLE_COLLECTSTATIC with the Value - 1 and PORT with the value of 8000 to the config vars
- The DISABLE_COLLECTSTATIC key-value pair must be removed prior to final deployment
- Back in your settings.py file, add the cloudinary libraries to the list of installed apps, the order they are inserted is important, 'cloudinary_storage' goes above 'django.contrib.staitcfiles' and 'cloudinary' goes below it
- Scroll down near the end of the file and below STATIC_URL add the STATIC files settings - the url, storage path, directory path, root path, media url and default file storage path
- Link the file to the templates directory in Heroku TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
- Change the templates directory to TEMPLATES_DIR - 'DIRS': [TEMPLATES_DIR]
- Add Heroku hostname into ALLOWED_HOSTS - the format will be the app name given in Heroku when creating the app followed by .herokuapp.com
- In your IDE, create three new top-level folders, media, static, templates
- Create a new file on the top level directory called 'Procfile' and add the following code to it web: guincorn PROJECT_NAME.wsgi
- In the terminal, save files, add the changed files, commit and push to GitHub
- In Heroku go to the "Deploy" tab and scroll down to the "Deployment Method" section
- Select "GitHub" as the method and click "Connect to GitHub"
- Scroll down to the "Connet to GitHub" section and search for the repository name you wish to deploy. Do this by typing in the depository name and click the "Search button
- Once the repository has been found, connect it by clicking the "Connect" button next to its name
- Choose "Automatic deploys" or "Manual deploys" to deploy your application - watch the build logs for any errors.
- Heroku will now build the app for you. Once it has completed the build process you will see a 'Your App Was Successfully Deployed' message and a link to the app to visit the live site.
You can fork the GitHub repository to make a copy of the original to view and change without affecting the original. This can be done by:
- Log into GitHub or create an account
- Locate the repository at https://github.com/Jbachtiger/ci-pp4-the-unconventional-programmer
- At the top of the repository, on the right-hand side of the page you will see an option to select "Fork" from the available buttons
- Click the fork button and a copy of the repository will have been created
You can create a clone of your repository by:
- Locate the repository you wish to clone https://github.com/Jbachtiger/ci-pp4-the-unconventional-programmer
- Click the arrow on the 'Code' button at the top of the list of files
- Select the clone by https and copy the URL using the provided clipboard
- Navigate to your chosen code editor and within the terminal change the directory to the location your to clone the repository to
- Type 'git clone' and paste the https link you copied from GitHub
- Press enter and git will clone the repository to your local machine
- Dev - this website was used as a guide to creating a profile page - code was amended to my projects specific needs
- I Think Therefore I Blog - code used for likes authentication and amended to suit my project
The content for the blog post was taken purely for illustrative purposes and not written by me. Below are the details of who wrote each post and where it was taken from:
- Code Academy - Coding Projects for Beginners
- Create Learn - Easy Games to Code
- Zero To Mastery - Programmer Success Stories
- Harvey Ramer - Stop Coding Under Stress: How to Avoid Bugs and the End of the World
- Code Academy - 10 Learner Stories Code
- Rescue Time - How to get work done when your not feeling it
- The Muse - 5 different types of imposter syndrome and 5 ways to battle each one
All images used in the blog posts were taken directly from the post's sources as detailed above in the content section.
- Stack Overflow - post helped my understanding of how to show active links in the Django navigation bar
- PyPi - provided further reading on how to use django active links
- Django CKeditor - provided documentation of how the ckeditor works
- Kerstin Martin - provided useful information as to how it is possible to automatically update the footer date each year
- CSS Tricks - used to read up on various ways to create a sticky footer
- Selmi Tech - used to understand how to implement comments functionality in my post-detail page
- Learn Django - helped gain a deeper understanding of how Django slugs work
- Codemy - provided ideas as to what functionality to add to a blog website and how Django can be utilised
- I Think Therefore I Blog Walkthrough - used to understand and reinforce concepts
- Django Summernote - the documentation was helpful in figuring out how to use Summernote and make it responsive
- My mentor for their support, advice and patience when reviewing this project with me
- The Code Institute slack community for always being on hand to ask questions and pointing me in the right direction
- Tutor support for their gudiance in solving bugs and pointing me in the right way to fix issues
- My partner, for being so patient with me whilst creating this project and for testing the website