An inventory management system is a crucial tool for businesses, providing a systematic approach to overseeing the entire lifecycle of goods.
By constantly monitoring inventory levels, the system enables companies to make informed decisions regarding when to restock, preventing 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 to meet customer demand without incurring unnecessary holding costs or experiencing disruptions due to stockouts.
Code B developers have been very effective at providing similar Enterprise application development for a very long time.
Note that you might need to set path variables 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 additional Python packages which we will install on the go.
We have listed a group of Python packages for data science application-building projects.
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.
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.
code python-ims
STEP 3 :
Let's create a virtual environment for our project.
A virtual environment, or venv, is a built-in Python module that helps create and manage isolated Python environments.
It allows developers to encapsulate project dependencies, ensuring that each project operates independently without interfering with the global environment.
This command will create a virtual environment for us.
python -m venv venv
Let's break down the above command
STEP 4 :
Now we will activate the virtual environment that we just created by using the following command in the terminal.
You will be able to see that a new environment is started in the terminal with the name venv in the braces.
If you want to exit out of the venv just type the following command in the terminal.
deactivate
STEP 5 :
Let's download the dependencies which we will use for our inventory management system. As we discussed prior we will use Flask framework for our project and Mongodb for the database we will download those using pip now.
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.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
We will start by importing the dependencies into our main file.
app.py
from flask import Flask, render_template, request, redirect, url_for
from pymongo import MongoClient
from bson import ObjectId
One by one let's understand what we have imported:-
Let's now connect our app with Mongodb so we can perform database operations on it. Add the following lines after initializing our app in the app.py file.
app = Flask(__name__)
client = MongoClient("your-mongo-srv")
db = client["inventory"]
collection = db["items"]
One by one lets break down the code that we just added
1 . Flask Setup :
Here, we are creating an instance of the Flask class and assigning it to the variable app.
app = Flask(__name__)
2. MongoDB Connection :
The argument provided to the MongoClient is the connection string for our MongoDB server.
# replace "your-mongo-srv" with your mongo string
client = MongoClient("your-mongo-srv")
3. Database and Collection Selection :
After connecting to our MongoDB server, we are creating a database inventory and collection items within that database.
db = client["inventory"]
collection = db["items"]
Before writing our APIs let's understand what an API 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.
Let's commence the development of our APIs.
Our webapp will have many different api routes. Lets start with our home route.
@app.route('/')
def index():
items = collection.find()
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.
@app.route('/add_item', methods=['POST'])
def add_item():
if request.method == 'POST':
item_name = request.form['item_name']
quantity = int(request.form['quantity'])
price = float(request.form['price'])
item = {
'item_name': item_name,
'quantity': quantity,
'price': price
}
collection.insert_one(item)
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 a bit different from the last one as will also accept params in the api route. We will first write the API and then discuss it.
@app.route('/update_item/<item_id>', methods=['GET', 'POST'])
def update_item(item_id):
item = collection.find_one({'_id': ObjectId(item_id)})
if request.method == 'POST':
new_quantity = int(request.form['new_quantity'])
new_price = float(request.form['new_price'])
collection.update_one(
{'_id': ObjectId(item_id)},
{'$set': {'quantity': new_quantity, 'price': new_price}}
)
return redirect(url_for('index'))
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 call 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 the GET method. After editing our details and clicking on update will will send a POST request to update the document.
You can see that we are separating 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 existing field values with the new ones using the $set operator from Mongodb.
Now let’s create our final API which will be the "/delete_item" API. This route is like the update route i.e. it will also accept the item_id parameter in the API route.
@app.route('/delete_item/<item_id>')
def delete_item(item_id):
collection.delete_one({'_id': ObjectId(item_id)})
return redirect(url_for('index'))
This API is quite small compared to the other APIs.
We will 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 our app.py would look like this.
from flask import Flask, render_template, request, redirect, url_for
from pymongo import MongoClient
from bson import ObjectId
app = Flask(__name__)
client = MongoClient("mongodb+srv://local:local@local-cluster.crpsu8t.mongodb.net/")
db = client["inventory"]
collection = db["items"]
@app.route('/')
def index():
items = collection.find()
return render_template('index.html', items=list(items))
@app.route('/add_item', methods=['POST'])
def add_item():
if request.method == 'POST':
item_name = request.form['item_name']
quantity = int(request.form['quantity'])
price = float(request.form['price'])
item = {
'item_name': item_name,
'quantity': quantity,
'price': price
}
collection.insert_one(item)
return redirect(url_for('index'))
@app.route('/update_item/<item_id>', methods=['GET', 'POST'])
def update_item(item_id):
item = collection.find_one({'_id': ObjectId(item_id)})
if request.method == 'POST':
new_quantity = int(request.form['new_quantity'])
new_price = float(request.form['new_price'])
collection.update_one(
{'_id': ObjectId(item_id)},
{'$set': {'quantity': new_quantity, 'price': new_price}}
)
return redirect(url_for('index'))
return render_template('update_item.html', item=item)
@app.route('/delete_item/<item_id>')
def delete_item(item_id):
collection.delete_one({'_id': ObjectId(item_id)})
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
We have completed the API side of the code.
Now just a few HTML divs here and there and we will have our inventory management system ready!
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:
Let's 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inventory Management System</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<style>
h1 {
color: #333;
}
form {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
max-width: 300px;
margin: auto;
}
label {
margin-bottom: 8px;
}
.no-items-message {
color: #555;
margin-top: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1 class="display-4 d-flex justify-content-center w-100">Inventory Management System</h1>
<form action="{{ url_for('add_item') }}" method="post" class="mt-4">
<div class="mb-3">
<label for="item_name" class="form-label">Item Name:</label>
<input type="text" name="item_name" class="form-control" required>
</div>
<div class="mb-3">
<label for="quantity" class="form-label">Quantity:</label>
<input type="number" name="quantity" class="form-control" required>
</div>
<div class="mb-3">
<label for="price" class="form-label">Price:</label>
<input type="number" name="price" step="0.01" class="form-control" required>
</div>
<button type="submit" class="btn btn-success mt-3">Add Item</button>
</form>
{% if items %}
<table class="table mt-4">
<thead>
<tr>
<th scope="col">Item Name</th>
<th scope="col">Quantity</th>
<th scope="col">Price</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.item_name }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.price }}</td>
<td>
<a href="{{ url_for('update_item', item_id=item._id) }}" class="btn btn-warning btn-sm">Update</a>
<a href="{{ url_for('delete_item', item_id=item._id) }}" class="btn btn-danger btn-sm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="no-items-message display-6">No items to display.</p>
{% endif %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Our home page would look like this in the browser
After we add an item to our database, the item will be displayed like this
Let's go ahead and fill in the update_item.html file that we created.
update_item.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update Item</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
h1 {
color: #333;
}
.custom-container {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
form {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 300px;
display: flex;
flex-direction: column;
align-items: center;
}
label {
margin-bottom: 8px;
}
input {
margin-bottom: 16px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 8px;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container custom-container">
<h1 class="mt-5">Update Item</h1>
<form action="{{ url_for('update_item', item_id=item._id) }}" method="post" class="mt-4">
<div class="mb-3">
<label for="new_quantity" class="form-label">New Quantity:</label>
<input type="number" name="new_quantity" value="{{ item.quantity }}" class="form-control" required>
</div>
<div class="mb-3">
<label for="new_price" class="form-label">New Price:</label>
<input type="number" name="new_price" step="0.01" value="{{ item.price }}" class="form-control" required>
</div>
<button type="submit" class="btn btn-success">Update Item</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
So clicking on the 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.
Clicking on the 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".
This way, we have finished the HTML part as well. Now we have an inventory management system that can perform basic operations on data.
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
You can always opt for hiring experienced companies for Python development projects.
Speaking of future enhancements, there can be multiple number of future enhancements by adding:
These are just a few enhancements that can be done.
Here's the link to the GitHub repository which contains the above code.
That's all from my side. Happy Coding!