project / August 15th, 2021
The Coffee Connect is a web app that displays a list of cafes for different areas in London from a database. The image for each cafe is rendered in the home page, and a user can get quick details on name, pricing, seating, Wi-Fi, sockets, bathrooms, and phone availability for that cafe by hovering their mouse over the image. A Google Maps link is also provided if the user wants the exact location and contact information for a cafe. A user can also choose to add a new cafe, edit the details of an existing cafe, or delete a cafe from the list.
This is a professional portfolio project that was created after completing the 100 Days of Code Python Bootcamp.
After completing the 100 Days of Code Python Bootcamp, this project was offered as a suggested project idea to apply my knowledge of web development with the Flask and SQLAlchemy Iibraries from the course to build full-stack web applications. Learning to pick a pre-made Bootstrap template and configure it with my knowledge of Python, HTML, and CSS to suit my needs was another useful challenge that helped build my web development skills. Just like other professional portfolio projects, developing skills in planning and executing a project from scratch without guidance was the most valuable lesson.
Python
Flask
Jinja
SQLAlchemy
Bootstrap
HTML
CSS
Heroku
DB Browser
Through building this web app, I wanted to allow users to view the list of cafes from a database and have the option to add new cafes and edit or delete existing cafes through the front-end. Essentially, the user should be able to perform the CRUD (create, read, update, delete) operations that every database should have, but with the ease of buttons and forms on a website instead of having to write SQL code themselves.
After looking through numerous website templates on HTML5Up, Start Bootstrap, and BootstrapMade, I decided to use the Sailor business template from BootstrapMade because of the clean and simple interface.
After downloading the template files to my project folder and moving the HTML files to a new folder called static, I used my knowledge of Flask and HTML to configure the Sailor index/home page and wrote Python code to render this page in the root route. Configuring the Sailor pages means fixing the HTML so that the styling and images appear and the links work dynamically and not statically. I also removed the sections and links that were not needed, and moved the header/navigation and footer code into their own HTML templates that can be used on every page for the website with the help of Jinja tags. Ultimately, I decided to have three pages: a home page that displays all cafes in the database, a page for adding cafes, and a page for editing existing cafes in the database. Once I decided on this structure, I added more Flask routes in my Python file to render each of these pages.
The next big step was to import SQLAlchemy so that the cafe records in the database could be mapped into Cafe objects. After connecting my Python file to the cafes SQLite database, I created a class called Cafe (inherited from the database Model class) to specify the structure every cafe record should have. This includes fields for an ID, name, a Google Maps link, an image link, a location, number of seats, coffee price, and whether or not the cafe has electrical sockets, toilets, Wi-Fi, and is able to take phone calls. Later on, the Cafe class can be used to query the cafes database, or add new cafes to it. Before writing database commands, I first use the Flask-WTF and Flask-Bootstrap extensions to create a form so that the user can enter information for each Cafe field, either to add a new cafe or edit an existing cafe. These forms are then inserted into the Add Cafe and Edit Cafe pages.
The first operation I wrote code for was the read command. This command would read all cafes from the database and display them in the home page, underneath the slide show of images. Initially, I wasn't planning on using the portfolio section for the Sailor template and was planning to render each cafe as a Bootstrap Card component. However, after looking at the HTML and CSS code for this section, I realized that I could use my knowledge of Jinja to render each cafe inside the portfolio section as an image and change the entire section to a cafes section, with the added bonus of already having buttons to filter for a field like location at the top of the section. By using a FOR loop, I was able to loop through the cafe locations and render them as filter buttons at the top of the cafes section. Another FOR loop was then used to loop through each cafe record and render their image and information below the filter buttons. I also used the FontAwesome Content Delivery Network to add custom buttons for deleting a cafe, editing a cafe, and opening the Google Maps link for a cafe.
The next user operation to complete was to create a new record, or add a new cafe. After a validated POST request to the add_cafe route, I wrote code to access the data in the Flask-WTF form that was filled out by the user in the add cafe page, in order to get the values for each field.
These field values are then used to create a new cafe record using the Cafe class. The new record is added and committed to the cafes database and the user is redirected to the home route to see a new list of cafes, with the new cafe added. In this case, since a new location was also added to the database, a new location filter button is added to the top of the cafes section.
The update command to edit an existing cafe follows a similar process to the create command. Clicking the edit button for a cafe will redirect the user to the edit cafe page which is similar to the add cafe page, but will contain pre-loaded values from the cafe in the form. This is because clicking the edit button will pass the cafe database ID as an argument to the edit_cafe route, which is used to query that cafe and its information in the cafes database.
After a validated POST request to the edit_cafe route, the field values in the form are used to overwrite the same fields for the cafe to be edited. These changes are committed and the user is redirected to the home route with the updated cafe shown.
The last operation to complete is the delete command, which is very simple. After the delete button for a cafe is pressed, a GET request is made to the delete_cafe route and the cafe ID is passed in. The ID is used to query the cafes database and the delete method is called to delete the matching cafe record. The changes are committed to the database and the user is redirected to the home route, with the deleted cafe no longer rendered.
After I finished writing code for the CRUD database operations, I tested the app to ensure each command was working correctly. I also considered adding authentication to ensure the Admin would be the only user who can delete cafes, but decided against it due to time constraints. Another reason for not including authentication is because since this was a portfolio project, I wanted visitors to be able to test out the different operations on the website without having to worry about signing up and logging in.
Before deploying this app on Heroku, I installed the psycopg2-binary library to enable the app to use the Heroku Postgres database instead of an SQLite database and installed gunicorn so that the app can connect to Heroku and become a production-mode app instead of a development-mode app. I also created a requirements.txt file so that users can check which libraries were installed in the creation of this project and an environmental variables file to protect sensitive information. A .gitignore file and Procfile are also created as necessary items before deployment. After updating the database URI from the local SQLite database to the Heroku Postgres database, I deployed this app by committing the project to a GitHub repository and connecting to it with Heroku.
Creating this website was another valuable experience in creating a useful full-stack web application, from the planning stages to the deployment stage. Unlike the Height Data Collector app, I used a Bootstrap template and had to configure it to suit my needs, which presented a different challenge than having to create it from scratch. Looking at this project can also serve as a starting point for other projects that would use the CRUD database operations.
As I stated in the process section, adding authentication to restrict certain commands for only admin users would be helpful, given more time. At the same time, this is a portfolio project and it also helps to allow visitors and potential employers test out the different operations without having to signing up and log in. This app can also be further improved by adding options to filter for different fields like price and seating.