Blogs

calendar img
shagun-deogharkar
Shagun DeogharkarSoftware Engineer @ Code-Bauthor linkedin

Guide to building an Inventory Management System in Python

img

What is Inventory Management System ?

An inventory management system serves as a crucial tool for businesses, providing a systematic approach to oversee the entire lifecycle of their goods. By constantly monitoring inventory levels, the system enables companies to make informed decisions regarding when to restock, preventing both excess inventory and stock shortages. It encompasses order processing, tracking sales, and managing deliveries, facilitating a seamless flow of information across various departments. The overarching objective is to strike a delicate balance, ensuring that a company always has the right amount of stock on hand to meet customer demand without incurring unnecessary holding costs or experiencing disruptions due to stockouts.

Prerequisites for developing Inventory Management System(IMS).

  • To efficiently write our code, we'll utilize Visual Studio Code, commonly known as VS Code, as our code editor. If you don't have VS Code installed, you can download it from their official website. Note that it is not necessary to use VS Code, you can use any code editor of your choice.
  • Some understanding about python, html and css.
  • Since our project is based on Python, it's imperative to have Python installed on your system. You can install the latest stable version of Python by visiting the offical website. I am using Python 3.10.12.
  • After we have successfully installed python, we will now install pip. Now, what is pip? pip is the package installer for Python. More about pip here. You can install pip using the official documentation.

Note that you might need to set path variable in your system's environment variables if you are using windows. To set the path variable you can refer to this answer on stack overflow. We will also need some additonal python packages which we will install on the go.

All prerequisites done let's dive into the python world.

We will be using python's Flask framework for our web app. Flask is a simple and flexible web framework for Python. It helps developers easily build web applications without unnecessary complexity. Flask's lightweight design makes it a popular choice for creating management systems apps, allowing for efficient and straightforward development with minimal code.


STEP 1 :

First of all we will create a folder for our project, you can do this by simply creating a folder by right clicking > new folder or the other way is to execute the following command in the terminal.

1$ mkdir python-ims


STEP 2 :

After you have successfully created a folder open it in VS Code by executing the following command in the terminal.

1$ code python-ims


STEP 3 :

Let's create an virtual environment for our project. What is a virtual environment? (or virtual environment) is a built-in Python module which helps to create and manage isolated Python environments. It allows developers to encapsulate project dependencies, ensuring that each project operates in its own environment without interfering with the global. This will command will create an virtual environment for us.

1$ python -m venv venv


STEP 4 :

Now we will activate the virtual environment that we just created by using the following command in the terminal.

Windows

.\venv\Scripts\activate

Linux or Mac Os

source venv/bin/activate

If you want to exit out of the venv just type the following command in the ternimal.

1$ deactivate

You will be able to see that a new environment is started in the terminal with the name venv in the braces


STEP 5 :

Lets download the dependencies which we will use for our invenotry management system. As we discussed about prior that we will use Flask framework for our project and mongodb for database we will download those using pip now.

1$ pip install Flask pymongo

We have now downloaded the required dependencies and we are all set now.


STEP 6 :

Create an app.py file in the root directory of the project which will have all the code. Head over to the official flask documentation and copy the template code for our app.py file. The template code looks like this.

1from flask import Flask
2
3app = Flask(__name__)
4
5@app.route("/")
6def hello_world():
7 return "<p>Hello, World!</p>"



Importing our packages into our app.py file

We will start by importing the dependencies into our main file.

app.py

1from flask import Flask, render_template, request, redirect, url_for
2from pymongo import MongoClient
3from bson import ObjectId

One by one let's understand what we have imported :-

Flask as we know, we will be using it for our web application.

render_template is used to render HTML templates. It is commonly used to generate HTML pages dynamically.

request contains the incoming request data from the client. It is used to access form data, file uploads, and other information sent in the HTTP request.

redirect is used to redirect the user to a different endpoint.

url_for is used to generate URLs for the given endpoint.

MongoClient is used to connect to our mongodb server.

ObjectId will help us convert string id into mongo db _id.

Initializing our flask app and connecting to our mongodb server.

Let's now connect our app with mongodb so we can perform database operations on it. Add the following lines after initialziing the our app.

1app = Flask(__name__)
2client = MongoClient("your-mongo-srv")
3db = client["inventory"]
4collection = db["items"]

1 . Flask Setup :

1app = Flask(__name__)

Here, we are creating an instance of the Flask class and assigning it to the variable app.


2. MongoDB Connection :

1# replace "your-mongo-srv" with your mongo string
2client = MongoClient("your-mongo-srv")

The argument passed to the MongoClient is t the connection string of our MongoDB server.


3. Database and Collection Selection :

1db = client["inventory"] 
2collection = db["items"]

After connecting to our MongoDB server, we are creating a database inventory and collection items within that database.

Coding our APIs

Before writing our apis let's understand what an API actually is. An API(Application Programming Interface) is like a magic messenger that lets different computer programs talk to each other. It's like asking a robot friend to fetch a toy for you – you tell the robot what you want, and it brings it back. Similarly, an API lets one program ask another program for information or help, making things work together smoothly! For instance, if you ask a weather API, it can tell your game what the weather is like, so your game knows whether it should be sunny or rainy. Here's a demonstration of how a Twitter API can be utilized to create bots on the platform using Python.

inventory-management-system-API

Let's commence the development of our APIs.

Our webapp will have many different api routes. Lets start with our home route.


1@app.route('/')
2def index():
3 items = collection.find()
4 return render_template('index.html', items=list(items))


@app.route('/') decorator is used in Flask to define a route for the specified URL ("/" in our case). When a user accesses the root URL of your application, the function index() will be called.


The index() function will find all the items from the collection (in our case we have defined the value of collection as items) will render the index.html page on client side and will pass the items to the html template. Generally home route urls are always ("/").


We are converting the items to list of documents because if we print the items that we get from database it will print something like this

<pymongo.cursor.Cursor object at 0x7f263d863910>

What is this wierd thing? a cursor is a pointer or iterator that points to a position within a set of data. When you execute a query, the database returns a cursor, and you can use this cursor to iterate over the result set.


Further moving on to the "/add_item" route. As the name suggest we will be using this route to add items to our inventory.

1@app.route('/add_item', methods=['POST'])
2def add_item():
3 if request.method == 'POST':
4 item_name = request.form['item_name']
5 quantity = int(request.form['quantity'])
6 price = float(request.form['price'])
7
8 item = {
9 'item_name': item_name,
10 'quantity': quantity,
11 'price': price
12 }
13
14 collection.insert_one(item)
15
16 return redirect(url_for('index'))


Whenever we will hit the "add_items" route the function add_item() will run. It will check if the request method is POST, will extract item details from the form data or you can also call it request body , and will create a dictionary representing the new item. This item will be inserted into our MongoDB collection using 'collection.insert_one(item)'. Finally, we will be redirected to the 'index' route, which is the main page of our website where the updated list of items will be displayed.


Let's move on to the "/update_item" api. This api will be bit different from the last one as will also accept params in the api route. We will first write the api and then discuss about it.

1@app.route('/update_item/<item_id>', methods=['GET', 'POST'])
2def update_item(item_id):
3 item = collection.find_one({'_id': ObjectId(item_id)})
4
5 if request.method == 'POST':
6 new_quantity = int(request.form['new_quantity'])
7 new_price = float(request.form['new_price'])
8
9 collection.update_one(
10 {'_id': ObjectId(item_id)},
11 {'$set': {'quantity': new_quantity, 'price': new_price}}
12 )
13
14 return redirect(url_for('index'))
15
16 return render_template('update_item.html', item=item)


Here you can see we are accepting the <item_id> parameter in the api. We can also can this route a dynamic route. We will use this id to fetch the item from our database and perform the update operation on it. Now you might be wondering why we have two request methods here "GET" and "POST". This is because when we click on the update button on the UI side we need to first get the item from db and pre-fill the form. For this we will use GET method. After editing our details and clicking on update will will send POST request to update the document. You can see that we are seperating the two requests using the if statement.

We are converting the item_id to _id(mongodb unique id) using the ObjectId function that we imported from bson package to fetch the right document from the database. After that we just extract the new content from the request body and replace the exisitng field values with the new ones using the $set operator from mongodb.

Lets now create our final api which will be "/delete_item" api. This route is like the update route i.e it will also aceept item_id paramter in the api route.

1@app.route('/delete_item/<item_id>')
2def delete_item(item_id):
3 collection.delete_one({'_id': ObjectId(item_id)})
4 return redirect(url_for('index'))


This api is quite small as compared to the other apis. We wil accept the id parameter from our route, convert it to mongodb ObjectId, delete it from the database using the delete_one function and finally redirect the user to the home page which in our case is the index.html page.


After completing our four api's our app.py would look like this.

1from flask import Flask, render_template, request, redirect, url_for
2from pymongo import MongoClient
3from bson import ObjectId
4
5app = Flask(__name__)
6client = MongoClient("mongodb+srv://local:local@local-cluster.crpsu8t.mongodb.net/")
7db = client["inventory"]
8collection = db["items"]
9
10
11@app.route('/')
12def index():
13 items = collection.find()
14 return render_template('index.html', items=list(items))
15
16
17@app.route('/add_item', methods=['POST'])
18def add_item():
19 if request.method == 'POST':
20 item_name = request.form['item_name']
21 quantity = int(request.form['quantity'])
22 price = float(request.form['price'])
23
24 item = {
25 'item_name': item_name,
26 'quantity': quantity,
27 'price': price
28 }
29
30 collection.insert_one(item)
31
32 return redirect(url_for('index'))
33
34
35@app.route('/update_item/<item_id>', methods=['GET', 'POST'])
36def update_item(item_id):
37 item = collection.find_one({'_id': ObjectId(item_id)})
38
39 if request.method == 'POST':
40 new_quantity = int(request.form['new_quantity'])
41 new_price = float(request.form['new_price'])
42
43 collection.update_one(
44 {'_id': ObjectId(item_id)},
45 {'$set': {'quantity': new_quantity, 'price': new_price}}
46 )
47
48 return redirect(url_for('index'))
49
50 return render_template('update_item.html', item=item)
51
52
53@app.route('/delete_item/<item_id>')
54def delete_item(item_id):
55 collection.delete_one({'_id': ObjectId(item_id)})
56 return redirect(url_for('index'))
57
58
59if __name__ == '__main__':
60 app.run(debug=True)


Hooreyyyyy!!!! 🎉🎉🎉 We have successfully completed the API side of the code. Now just few html divs here and there and we will have our inventory management system ready!

Building our frontend

We will create a folder with name templates in the root directory of our project. Create two html files inside the templates folder "index.html" and "update_item.html". Note that we need to name these files to the same names as we used in the app.py file.

Open your cmd and paste the following command to create the files:


Windows

mkdir templates && cd templates && echo. > index.html && echo. > update_item.html

Linux

mkdir templates && cd templates/ && touch index.html && touch update_item.html

Lets code our home page i.e index.html. This page will contain a form through which we can create an item and also the page will list all the items with two options [update, delete] next to them.


We will use bootstrap along with traditional css for our app. Check out how to integrate bootstrap into your project here.


After coding everything our index.html would look like this

1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>Inventory Management System</title>
8 <!-- Bootstrap CSS -->
9 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
10 <style>
11 h1 {
12 color: #333;
13 }
14
15 form {
16 background-color: #fff;
17 padding: 20px;
18 border-radius: 8px;
19 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
20 margin-bottom: 20px;
21 max-width: 300px;
22 margin: auto;
23 }
24
25 label {
26 margin-bottom: 8px;
27 }
28
29 .no-items-message {
30 color: #555;
31 margin-top: 20px;
32 text-align: center;
33 }
34 </style>
35</head>
36<body>
37 <div class="container mt-5">
38 <h1 class="display-4">Inventory Management System</h1>
39
40 <form action="{{ url_for('add_item') }}" method="post" class="mt-4">
41 <div class="mb-3">
42 <label for="item_name" class="form-label">Item Name:</label>
43 <input type="text" name="item_name" class="form-control" required>
44 </div>
45
46 <div class="mb-3">
47 <label for="quantity" class="form-label">Quantity:</label>
48 <input type="number" name="quantity" class="form-control" required>
49 </div>
50
51 <div class="mb-3">
52 <label for="price" class="form-label">Price:</label>
53 <input type="number" name="price" step="0.01" class="form-control" required>
54 </div>
55
56 <button type="submit" class="btn btn-success mt-3">Add Item</button>
57 </form>
58 {% if items %}
59 <table class="table mt-4">
60 <thead>
61 <tr>
62 <th scope="col">Item Name</th>
63 <th scope="col">Quantity</th>
64 <th scope="col">Price</th>
65 <th scope="col">Actions</th>
66 </tr>
67 </thead>
68 <tbody>
69 {% for item in items %}
70 <tr>
71 <td>{{ item.item_name }}</td>
72 <td>{{ item.quantity }}</td>
73 <td>{{ item.price }}</td>
74 <td>
75 <a href="{{ url_for('update_item', item_id=item._id) }}" class="btn btn-warning btn-sm">Update</a>
76 <a href="{{ url_for('delete_item', item_id=item._id) }}" class="btn btn-danger btn-sm">Delete</a>
77 </td>
78 </tr>
79 {% endfor %}
80 </tbody>
81 </table>
82 {% else %}
83 <p class="no-items-message display-6">No items to display.</p>
84 {% endif %}
85 </div>
86 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
87</body>
88</html>


Our home page would look like this in the browser


home-page

After we add an item to our database , the item will be displayed like this

home-page-with-items

Let's go ahead and fill the update_item.html file that we created.

update_item.html

1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>Update Item</title>
8 <!-- Bootstrap CSS -->
9 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
10 <style>
11 body {
12 font-family: 'Arial', sans-serif;
13 background-color: #f4f4f4;
14 margin: 0;
15 padding: 0;
16 display: flex;
17 align-items: center;
18 justify-content: center;
19 height: 100vh;
20 }
21
22 h1 {
23 color: #333;
24 }
25
26 .custom-container {
27 text-align: center;
28 display: flex;
29 align-items: center;
30 justify-content: center;
31 flex-direction: column;
32 }
33
34 form {
35 background-color: #fff;
36 padding: 20px;
37 border-radius: 8px;
38 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
39 width: 300px;
40 display: flex;
41 flex-direction: column;
42 align-items: center;
43 }
44
45 label {
46 margin-bottom: 8px;
47 }
48
49 input {
50 margin-bottom: 16px;
51 padding: 8px;
52 border: 1px solid #ccc;
53 border-radius: 4px;
54 }
55
56 button {
57 padding: 8px;
58 background-color: #4caf50;
59 color: #fff;
60 border: none;
61 border-radius: 4px;
62 cursor: pointer;
63 }
64 </style>
65</head>
66<body>
67 <div class="container custom-container">
68 <h1 class="mt-5">Update Item</h1>
69
70 <form action="{{ url_for('update_item', item_id=item._id) }}" method="post" class="mt-4">
71 <div class="mb-3">
72 <label for="new_quantity" class="form-label">New Quantity:</label>
73 <input type="number" name="new_quantity" value="{{ item.quantity }}" class="form-control" required>
74 </div>
75
76 <div class="mb-3">
77 <label for="new_price" class="form-label">New Price:</label>
78 <input type="number" name="new_price" step="0.01" value="{{ item.price }}" class="form-control" required>
79 </div>
80
81 <button type="submit" class="btn btn-success">Update Item</button>
82 </form>
83 </div>
84 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
85</body>
86</html>


So clicking on update button of any item would take us to the update page and would prefill the fields with the current values of that item. The update page would look like this.

upadting-item


Clicking on delete button would remove the item from the database and if there are no items in the database it will display "No items to display".


Woo-hoo! 🎉🎉🎉 we have finished the html part as well. Now we have ourself an inventory management system that can perform basic operations on data.

Summary

We created a basic CRUD (Create, Read, Update, Delete) web application using Flask and MongoDB. Our app allows users to interact with a simple database through a user-friendly interface, with functionality for adding, viewing, updating, and deleting records.


Future Enchancements

Speaking of future enhancements, there can be multiple number of future enhancements by adding:

  1. Validations for fields.
  2. authentications for users.
  3. filters for displaying records.
  4. deleting multiple records.
  5. calculating expenses of items.


These are just few enhancements that can be done.

Source Code

Here's the link to the github repository which contains the above code. That's all from my side. Happy Coding!