Project Report
Project Report
Submitted by
Devansh Suraj Singh Yash Sehgal
226320027 226301222 226301239
Course
Bachelor of Technology in Computer Science & Engineering
Instructor
Mr. Kuldeep Giri
Department
Department of Computer Science & Engineering
Faculty of Engineering and Technology
Gurukula Kangri(Deemed to be University)
Haridwar, Uttarakhand
CERTIFICATE
This is to certify that the project report titled
"Library Management System"
submitted by Devansh(226320027), Suraj Singh(226301222) & Yash
Sehgal(226301239, students of 6th Semester, Department of
Computer Science and Engineering, Faculty of Engineering &
Technology, Gurukula Kangri(Deemed to be University), Haridwar is
the original work completed under my supervision and guidance.
The work has been reviewed and is found to be satisfactory.
Date: _____________
Signature of Instructor
Mr. Kuldeep Giri
Assistant Professor
Department of Computer Science and Engineering,
Faculty of Engineering & Technology,
Gurukula Kangri(Deemed to be University),
Haridwar
ABSTRACT
The Library Management System is a Python-based application
designed to streamline and simplify common library operations such as
book and member management, book issuing and returns, and tracking
late returns. Built using tkinter for the graphical user interface and
pandas for data manipulation, the project aims to digitize manual
processes and enhance efficiency through a user-friendly desktop
application. All records are maintained in CSV files, making the solution
lightweight and portable.
INTRODUCTION
Library management is a crucial part of any educational institution.
Manual systems are often inefficient, error-prone, and difficult to
manage at scale. This project addresses those issues by automating key
library operations. It provides an easy-to-use graphical interface, which
reduces complexity for the end user and ensures consistent data
handling using structured formats.
FEATURES
• Add new books: add_book_gui - Input ID, title, author, cost; saves
to Books.csv.
• Add new members: add_member_gui - Input ID, name, contact;
saves to Members.csv.
• Delete books: delete_book_gui - Delete by Book ID from
Books.csv if not issued.
• Delete members and issued records:
• Members: delete_member_gui - Delete by Member ID from
Members.csv.
• Issued: delete_issue_gui - Delete by Book ID from Issued.csv.
TECHNOLOGY USED
import pandas as pd
from datetime import datetime
import tkinter as tk
from tkinter import ttk, messagebox
class InputDialog:
def __init__(self, parent, title, fields):
self.top = tk.Toplevel(parent)
self.top.title(title)
self.top.geometry("300x" + str(100 + len(fields) * 40))
self.top.transient(parent)
self.top.grab_set()
self.result = None
self.entries = {}
self.top.wait_window()
def ok(self):
self.result = {field: entry.get() for field, entry in self.entries.items()}
self.top.destroy()
def cancel(self):
self.result = None
self.top.destroy()
class LibraryManagementGUI:
def __init__(self, root):
self.root = root
self.root.title("Library Management System")
self.root.geometry("800x600")
self.load_data()
self.setup_ui()
def load_data(self):
try:
self.books = pd.read_csv("Books.csv", dtype={'ID': str})
self.books['ID'] = self.books['ID'].astype(str)
except:
self.books = pd.DataFrame(columns=["ID", "Title", "Author", "Cost"])
self.books['ID'] = self.books['ID'].astype(str)
try:
self.members = pd.read_csv("Members.csv", dtype={'ID': str})
self.members['ID'] = self.members['ID'].astype(str)
except:
self.members = pd.DataFrame(columns=["ID", "Name", "Contact"])
self.members['ID'] = self.members['ID'].astype(str)
try:
self.issued = pd.read_csv("Issued.csv", dtype={'BookID': str, 'MemberID': str})
self.issued['BookID'] = self.issued['BookID'].astype(str)
self.issued['MemberID'] = self.issued['MemberID'].astype(str)
if 'Remark' not in self.issued.columns:
self.issued['Remark'] = ''
except:
self.issued = pd.DataFrame(columns=["BookID", "MemberID", "IssueDate", "ReturnDate", "ActualReturnDate", "Remark"])
self.issued['BookID'] = self.issued['BookID'].astype(str)
self.issued['MemberID'] = self.issued['MemberID'].astype(str)
self.issued['Remark'] = self.issued['Remark'].astype(str)
def save_data(self):
self.books.to_csv("Books.csv", index=False)
self.members.to_csv("Members.csv", index=False)
self.issued.to_csv("Issued.csv", index=False)
def setup_ui(self):
self.main_frame = ttk.Frame(self.root, padding="10")
self.main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
self.notebook = ttk.Notebook(self.main_frame)
self.notebook.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
self.create_books_tab()
self.create_members_tab()
self.create_issues_tab()
def create_books_tab(self):
books_tab = ttk.Frame(self.notebook)
self.notebook.add(books_tab, text="Books")
self.books_tree = ttk.Treeview(books_tab, columns=("ID", "Title", "Author", "Cost"), show="headings")
self.books_tree.heading("ID", text="ID")
self.books_tree.heading("Title", text="Title")
self.books_tree.heading("Author", text="Author")
self.books_tree.heading("Cost", text="Cost")
self.books_tree.grid(row=0, column=0, columnspan=4, pady=10)
ttk.Button(books_tab, text="Add Book", command=self.add_book_gui).grid(row=1, column=0, padx=5, pady=5)
ttk.Button(books_tab, text="Search Book", command=self.search_book_gui).grid(row=1, column=1, padx=5, pady=5)
ttk.Button(books_tab, text="Delete Book", command=self.delete_book_gui).grid(row=1, column=2, padx=5, pady=5)
ttk.Button(books_tab, text="Refresh", command=self.refresh_books).grid(row=1, column=3, padx=5, pady=5)
self.refresh_books()
def create_members_tab(self):
members_tab = ttk.Frame(self.notebook)
self.notebook.add(members_tab, text="Members")
self.members_tree = ttk.Treeview(members_tab, columns=("ID", "Name", "Contact"), show="headings")
self.members_tree.heading("ID", text="ID")
self.members_tree.heading("Name", text="Name")
self.members_tree.heading("Contact", text="Contact")
self.members_tree.grid(row=0, column=0, columnspan=4, pady=10)
ttk.Button(members_tab, text="Add Member", command=self.add_member_gui).grid(row=1, column=0, padx=5, pady=5)
ttk.Button(members_tab, text="Search Member", command=self.search_member_gui).grid(row=1, column=1, padx=5, pady=5)
ttk.Button(members_tab, text="Delete Member", command=self.delete_member_gui).grid(row=1, column=2, padx=5, pady=5)
ttk.Button(members_tab, text="Refresh", command=self.refresh_members).grid(row=1, column=3, padx=5, pady=5)
self.refresh_members()
def create_issues_tab(self):
issues_tab = ttk.Frame(self.notebook)
self.notebook.add(issues_tab, text="Issues")
self.issues_tree = ttk.Treeview(issues_tab,
columns=("BookID", "MemberID", "IssueDate", "ReturnDate", "ActualReturnDate", "Remark"),
show="headings")
self.issues_tree.heading("BookID", text="Book ID")
self.issues_tree.heading("MemberID", text="Member ID")
self.issues_tree.heading("IssueDate", text="Issue Date")
self.issues_tree.heading("ReturnDate", text="Expected Return")
self.issues_tree.heading("ActualReturnDate", text="Actual Return")
self.issues_tree.heading("Remark", text="Remark")
self.issues_tree.column("BookID", width=80)
self.issues_tree.column("MemberID", width=80)
self.issues_tree.column("IssueDate", width=100)
self.issues_tree.column("ReturnDate", width=100)
self.issues_tree.column("ActualReturnDate", width=100)
self.issues_tree.column("Remark", width=150)
self.issues_tree.grid(row=0, column=0, columnspan=4, pady=10)
ttk.Button(issues_tab, text="Issue Book", command=self.issue_book_gui).grid(row=1, column=0, padx=5, pady=5)
ttk.Button(issues_tab, text="Return Book", command=self.return_book_gui).grid(row=1, column=1, padx=5, pady=5)
ttk.Button(issues_tab, text="Delete Issue", command=self.delete_issue_gui).grid(row=1, column=2, padx=5, pady=5)
ttk.Button(issues_tab, text="Refresh", command=self.refresh_issues).grid(row=1, column=3, padx=5, pady=5)
self.refresh_issues()
def add_book_gui(self):
dialog = InputDialog(self.root, "Add Book", ["Book ID", "Title", "Author", "Cost"])
if dialog.result and all(dialog.result.values()):
book_id = str(dialog.result["Book ID"])
if book_id in self.books['ID'].values:
messagebox.showerror("Error", "Book ID already exists!")
return
new_row = pd.DataFrame([{
"ID": book_id,
"Title": dialog.result["Title"],
"Author": dialog.result["Author"],
"Cost": dialog.result["Cost"]
}])
self.books = pd.concat([self.books, new_row], ignore_index=True)
self.books['ID'] = self.books['ID'].astype(str)
self.save_data()
self.refresh_books()
messagebox.showinfo("Success", "Book added successfully!")
def search_book_gui(self):
dialog = InputDialog(self.root, "Search Book", ["Title"])
if dialog.result and dialog.result["Title"]:
result = self.books[self.books['Title'].str.contains(dialog.result["Title"], case=False, na=False)]
self.refresh_books(result)
def delete_book_gui(self):
dialog = InputDialog(self.root, "Add Book", ["Book ID"])
if dialog.result and dialog.result["Book ID"]:
book_id = str(dialog.result["Book ID"])
if book_id not in self.books['ID'].values:
messagebox.showerror("Error", "Book ID not found!")
return
if self.is_book_issued(book_id):
messagebox.showerror("Error", "Cannot delete - book is currently issued!")
return
self.books = self.books[self.books['ID'] != book_id]
self.save_data()
self.refresh_books()
messagebox.showinfo("Success", "Book deleted successfully!")
def add_member_gui(self):
dialog = InputDialog(self.root, "Add Member", ["Member ID", "Name", "Contact"])
if dialog.result and all(dialog.result.values()):
member_id = str(dialog.result["Member ID"])
if member_id in self.members['ID'].values:
messagebox.showerror("Error", "Member ID already exists!")
return
new_member = pd.DataFrame([{
"ID": member_id,
"Name": dialog.result["Name"],
"Contact": dialog.result["Contact"]
}])
self.members = pd.concat([self.members, new_member], ignore_index=True)
self.members['ID'] = self.members['ID'].astype(str)
self.save_data()
self.refresh_members()
messagebox.showinfo("Success", "Member added successfully!")
def search_member_gui(self):
dialog = InputDialog(self.root, "Search Member", ["Name"])
if dialog.result and dialog.result["Name"]:
result = self.members[self.members['Name'].str.contains(dialog.result["Name"], case=False, na=False)]
self.refresh_members(result)
def delete_member_gui(self):
dialog = InputDialog(self.root, "Delete Member", ["Member ID"])
if dialog.result and dialog.result["Member ID"]:
member_id = str(dialog.result["Member ID"])
if member_id not in self.members['ID'].values:
messagebox.showerror("Error", "Member ID not found!")
return
self.members = self.members[self.members['ID'] != member_id]
self.save_data()
self.refresh_members()
messagebox.showinfo("Success", "Member deleted successfully!")
def issue_book_gui(self):
dialog = InputDialog(self.root, "Issue Book", ["Book ID", "Member ID", "Issue Date (DD-MM-YYYY)", "Return Date (DD-MM-YYYY)"])
if dialog.result and all(dialog.result.values()):
book_id = str(dialog.result["Book ID"])
member_id = str(dialog.result["Member ID"])
if book_id not in self.books['ID'].values:
messagebox.showerror("Error", "Invalid Book ID!")
return
if member_id not in self.members['ID'].values:
messagebox.showerror("Error", "Invalid Member ID!")
return
if self.is_book_issued(book_id):
messagebox.showerror("Error", "Book is already issued!")
return
new_issue = pd.DataFrame([{
"BookID": book_id,
"MemberID": member_id,
"IssueDate": dialog.result["Issue Date (DD-MM-YYYY)"],
"ReturnDate": dialog.result["Return Date (DD-MM-YYYY)"],
"ActualReturnDate": None,
"Remark": ""
}])
self.issued = pd.concat([self.issued, new_issue], ignore_index=True)
self.issued['BookID'] = self.issued['BookID'].astype(str)
self.issued['MemberID'] = self.issued['MemberID'].astype(str)
self.save_data()
self.refresh_issues()
messagebox.showinfo("Success", "Book issued successfully!")
def return_book_gui(self):
dialog = InputDialog(self.root, "Return Book", ["Book ID", "Actual Return Date (DD-MM-YYYY)", "Remark"])
if dialog.result and all(v for k, v in dialog.result.items() if k != "Remark"):
book_id = str(dialog.result["Book ID"])
if book_id not in self.books['ID'].values:
messagebox.showerror("Error", "Invalid Book ID!")
return
actual_return_date = dialog.result["Actual Return Date (DD-MM-YYYY)"]
remark = dialog.result["Remark"] or ""
mask = (self.issued['BookID'] == book_id) & (self.issued['ActualReturnDate'].isna())
if mask.any():
self.issued.loc[mask, 'ActualReturnDate'] = actual_return_date
self.issued.loc[mask, 'Remark'] = remark
self.save_data()
try:
issue_row = self.issued[mask].iloc[0]
expected = datetime.strptime(issue_row['ReturnDate'], "%d-%m-%Y")
actual = datetime.strptime(actual_return_date, "%d-%m-%Y")
if actual > expected:
days_late = (actual - expected).days
messagebox.showwarning("Late", f"Book returned {days_late} day(s) late!")
else:
messagebox.showinfo("Success", "Book returned on time!")
except:
messagebox.showwarning("Warning", "Could not check late status (date format issue)")
self.refresh_issues()
else:
messagebox.showerror("Error", "Book not currently issued!")
def delete_issue_gui(self):
dialog = InputDialog(self.root, "Delete Issue", ["Book ID"])
if dialog.result and dialog.result["Book ID"]:
book_id = str(dialog.result["Book ID"])
if book_id not in self.issued['BookID'].values:
messagebox.showerror("Error", "Book ID not found in issued records!")
return
self.issued = self.issued[self.issued['BookID'] != book_id]
self.save_data()
self.refresh_issues()
messagebox.showinfo("Success", "Issued book record deleted successfully!")
def refresh_issues(self):
for item in self.issues_tree.get_children():
self.issues_tree.delete(item)
for _, row in self.issued.iterrows():
self.issues_tree.insert("", "end", values=(
str(row["BookID"]),
str(row["MemberID"]),
row["IssueDate"],
row["ReturnDate"],
row["ActualReturnDate"] if pd.notna(row["ActualReturnDate"]) else "",
row["Remark"] if pd.notna(row["Remark"]) else ""
))
if __name__ == "__main__":
root = tk.Tk()
app = LibraryManagementGUI(root)
root.mainloop()
SNAPSHOTS
• Add Book
• Search Book
• Delete Book
• Add Member
• Search Member
• Delete Member
• Issue Book
• Return Book
• Delete Issued Book Record
CONCLUSION
This project successfully demonstrates a functional, GUI-based Library
Management System using core Python libraries. It replaces tedious
manual operations with an efficient and visually intuitive interface. The
modular design allows for easy future enhancements such as
integrating databases, user authentication, or report generation.
FUTURE SCOPE
• Integration with SQLite or MySQL for large-scale use.
• Login system for admin and members.
• SMS/email notifications for due dates.
• Detailed report exports in PDF or Excel format.
APPENDIX
• Error Handling: Displays alerts for duplicate Book/Member IDs,
non-existent Book/Member IDs, attempts to issue already issued
books, or delete books that are currently issued, using
messagebox for user feedback.
• Data Formatting: Utilizes pandas for consistent data
management, ensuring IDs are treated as strings and handling CSV
file operations reliably with proper type enforcement.
• Late Return Check: Employs datetime to compare Actual Return
Date with Expected Return Date, calculates delay in days, and
shows warnings or success messages (no automatic remarks;
remarks are user-provided during return).
• New Additions: GUI includes buttons to delete books
(delete_book_gui), delete members (delete_member_gui), and
delete issued book records (delete_issue_gui). Each action
validates existence of Book ID or Member ID and, for books,
checks issuance status before proceeding.
• Patch Updates: Ensured delete book functionality remains intact
in the latest code, consistent with the original feature set, with
added validation to prevent deletion of issued books.