Implement a Shopping Cart in Python with Vultr Managed Databases for Caching

Updated on June 21, 2024
Implement a Shopping Cart in Python with Vultr Managed Databases for Caching header image

Introduction

The Redis® server is one of the most widely used open-source database solutions. Redis® stores all data in memory to enable low latency and high throughput. These benefits make Redis® suitable for storing shopping cart data for busy websites, especially during peak seasons.

When making orders from an e-commerce website, a customer usually selects items from a shopping list and then adds the items to a shopping cart. Under the hood, the shopping cart resides in a database. While it is practical to use relational databases to handle shopping cart data, such databases may not perform optimally with high number of users and their slowness can negatively affect users' experience.

Redis® has several functions that you can use to speed up the process of adding, removing, and displaying shopping cart data on your website. You can use the Redis® hset, hincrby, hdel, and hget commands in combination with a Redis® hash (a collection of field-value pairs) to achieve all shopping cart functionalities.

This guide shows you how to implement a shopping cart application with Python and Vultr Managed Database for Caching on Ubuntu 20.04 server.

Prerequisites

To follow along with this guide:

1. Create a Central Redis® Class

When designing Python applications, it is conventional to set up separate classes for basic functions to promote code reuse and reduce repetition. This guide uses a central Redis® class that handles different functions for adding, removing, deleting, and listing shopping cart items from the Redis® server. Follow the steps below to create the class:

  1. Begin by creating a project directory to separate your Python source code from the rest of the Linux files.

     $ mkdir project
  2. Switch to the new project directory.

     $ cd project
  3. Open a new redis_gateway.py file in a text editor.

     $ nano redis_gateway.py
  4. Enter the following information into the redis_gateway.py file. Replace the db_host, db_port, and db_pass values with the correct database information from your Vultr Managed Database for Caching.

     import redis
    
     class RedisGateway:
    
         def __init__(self):
    
             db_host = 'SAMPLE_DB_HOST_STRING.vultrdb.com'
             db_port = 16752
             db_pass = 'EXAMPLE_PASSWORD'   
    
             self.redisClient = redis.Redis(host = db_host, port = db_port, password = db_pass, ssl = 'true')
    
         def add_to_cart(self, json_payload):
    
             cart_id = json_payload["cart_id"]
             product_name = json_payload["product_name"]
             quantity = json_payload["quantity"]
    
             if self.redisClient.hexists(cart_id , product_name):
    
                 self.redisClient.hincrby(cart_id , product_name, quantity)
    
             else:   
    
                 self.redisClient.hset(cart_id, product_name, quantity)                   
    
             return "Item added to cart successfully."
    
         def remove_from_cart(self, json_payload):
    
             cart_id = json_payload["cart_id"]
             product_name = json_payload["product_name"]
    
    
             if self.redisClient.hexists(cart_id, product_name):
    
                 self.redisClient.hdel(cart_id, product_name)
    
                 return "Item removed from cart."
    
             else:   
    
                 return "Item not found from cart."
    
         def get_cart(self, cart_id):
    
             result = self.redisClient.hgetall(cart_id)        
    
             return result
  5. Save and close the redis_gateway.py file.

The redis_gateway.py file explained

  • The redis_gateway.py file has one RedisGateway class.

  • The RedisGateway class has four methods.

    1. The __init__() function fires when you import and initialize the class for the first time.

    2. The add_to_cart(..., json_payload) function takes a json_payload containing the cart_id, the product_name, and the quantity that you are adding to the cart. Under the add_to_cart() function, you're first checking if a cart exists in the Redis® server by running the self.redisClient.hexists function. If the cart exists, you're using the self.redisClient.hincrby... command to add the new quantity to the cart. Otherwise, if a cart with the defined cart_id doesn't exist, you're creating it from scratch. Then, you're using the self.redisClient.hset(cart_id, product_name, quantity) command to add the new product name and the quantity.

    3. The remove_from_cart(self, json_payload) function accepts a JSON payload with the name of the product you want to remove from the cart. You're using the logical if self.redisClient.hexists(cart_id, product_name): statement to check if the product exists in the Redis® server before issuing the self.redisClient.hdel(cart_id, product_name) command.

    4. The get_cart(..., cart_id) function takes the cart_id and queries the Redis® server to list all items in the cart using the self.redisClient.hgetall(cart_id) command.

  • The RedisGateway is now ready. You can reference it in other source code files and use its methods using the following syntax:

      import redis_gateway  
      rg = redis_gateway.RedisGateway()
    
      resp = rg.add_to_cart(json_payload);
      resp = rg.remove_from_cart(json_payload);
      resp = rg.get_cart(cart_id);

With a central Redis® gateway ready, follow the next step to create the main file for your application.

2. Create the Main Python File

Every Python application must have a main file that fires when you start the application. This guide uses the main.py file as the starting point. Create the file by following the steps below:

  1. Open a new main.py file in a text editor.

     $ nano main.py
  2. Enter the following information into the main.py file.

     import http.server
     from http import HTTPStatus
     from urllib.parse import urlparse, parse_qs
    
     import socketserver
     import json
    
     import redis_gateway        
    
     class httpHandler(http.server.SimpleHTTPRequestHandler):
    
         def do_POST(self):
    
             content_length = int(self.headers['Content-Length'])
             post_data = self.rfile.read(content_length)
    
             json_payload = json.loads(post_data) 
    
             self.send_response(HTTPStatus.OK)
             self.end_headers()
    
             rg = redis_gateway.RedisGateway()
    
             resp = rg.add_to_cart(json_payload);                
    
             self.wfile.write(bytes(resp + '\r\n', "utf8"))
    
         def do_DELETE(self):
    
             content_length = int(self.headers['Content-Length'])
             post_data = self.rfile.read(content_length)
    
             json_payload = json.loads(post_data) 
    
             self.send_response(HTTPStatus.OK)
             self.end_headers()
    
             rg = redis_gateway.RedisGateway()
    
             resp = rg.remove_from_cart(json_payload);                
    
             self.wfile.write(bytes(resp + '\r\n', "utf8"))
    
         def do_GET(self):
    
             self.send_response(HTTPStatus.OK)
             self.end_headers()
    
             parsed_url = urlparse(self.path)
             params = parse_qs(parsed_url.query)
    
             cart_id = params['cart_id'][0]
    
             rg = redis_gateway.RedisGateway()  
    
             cart = rg.get_cart(cart_id)
    
             data = { y.decode('ascii'): cart.get(y).decode('ascii') for y in cart.keys() }
    
             resp = json.dumps(data, indent = 4, separators = (',', ': '))    
    
             self.wfile.write(bytes(resp + "\r\n", "utf8"))
    
     httpServer = socketserver.TCPServer(('', 8080), httpHandler)
    
     print("HTTP server started at port 8080...")
    
     try:
    
         httpServer.serve_forever()
    
     except KeyboardInterrupt:
    
         httpServer.server_close()
         print("The server is stopped.")
  3. Save and close the main.py file.

The main.py file explained

  • The import ... section allows you to import all the necessary Python modules required by your application. The http.server, HTTPStatus, urlparse, parse_qs, and socketserver modules offer HTTP functionalities to the application. The json module allows you to format responses in the standard JSON response. Then, to connect to the Redis® server, you're importing your custom redis_gateway module.

  • The httpHandler class handles all HTTP methods. These are, POST, DELETE, and GET. These methods match the following shopping cart functions.

    • POST: rg.add_to_cart(...). Adds items to cart.
    • DELETE: rg.remove_from_cart(...). Removes items from the cart.
    • GET: rg.get_cart(...). Lists all items from the cart.
  • The httpServer = socketserver.TCPServer(('', 8080), httpHandler) statement starts an HTTP server on port 8080 and declares httpHandler as the handler class.

Your application is now ready. Follow the next step to test the application.

3. Test the Redis® Shopping Cart Application

The final step is installing third-party Python modules required by your application and running a few tests to ensure everything is working.

  1. Install the Python pip package. This is a tool for downloading and installing Python modules.

     $ sudo apt update
     $ sudo apt install -y python3-pip
  2. Use the pip package to install the redis module for Python.

     $ pip install redis
  3. Run the application using the python3 command followed by the start-up main.py file.

     $ python3 main.py

    Output.

     HTTP server started at port 8080...
  4. Establish another SSH connection to the server and use the Linux curl command to send the following requests to the application.

    • Add three items to a cart using abc as the cart_id.

        $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH", "quantity": "4"}'
      
        $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "4G WIRELESS ROUTER", "quantity": "7"}'
      
        $ curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "500W JUICER", "quantity": "2"}'

      Output.

        ...
        Item added to cart successfully.
    • Retrieve items from the cart.

        $ curl -X GET 'http://localhost:8080?cart_id=abc'

      Output.

        {
            "SMART WATCH": "4",
            "4G WIRELESS ROUTER": "7",
            "500W JUICER": "2"
        }
    • Remove a single item from the cart.

        $ curl -X DELETE http://localhost:8080/ -H 'Content-Type: application/json' -d '{"cart_id": "abc", "product_name": "SMART WATCH"}'

      Output.

        Item removed from cart.

Conclusion

This guide implements a shopping cart solution with Python and Vultr Managed Database for Caching on Ubuntu 20.04 server. Use the sample source code in this guide when creating your next shopping cart application. The Redis® shopping cart implementation enhances users' experience by allowing your application to handle many orders during peak.

Read the following documents to learn more about Redis® use cases.