۱۶
پروژه نهایی با پایتون عادی
ساخت یک سیستم مدیریت کتابخانه کامل با استفاده از تمام مفاهیم آموخته شده.
هدف پروژه
در این درس، یک سیستم مدیریت کتابخانه کامل میسازیم که شامل مدیریت کتابها، اعضا، امانتها و گزارشگیری است. این پروژه تمام مفاهیم آموخته شده در دوره را به کار میگیرد.
ویژگیهای اصلی:
- • مدیریت کتابها (افزودن، حذف، جستجو)
- • مدیریت اعضای کتابخانه
- • سیستم امانت و بازگشت کتاب
- • گزارشگیری و آمار
مفاهیم استفاده شده:
- • کلاسها و شیءگرایی
- • فایلها و JSON
- • Exception Handling
- • Regular Expressions
ساختار پروژه
ساختار فایلها
library_management/
├── main.py # فایل اصلی برنامه
├── models/
│ ├── book.py # کلاس کتاب
│ ├── member.py # کلاس عضو
│ └── loan.py # کلاس امانت
├── managers/
│ ├── library_manager.py # مدیر کتابخانه
│ └── file_manager.py # مدیریت فایلها
├── utils/
│ ├── validators.py # اعتبارسنجی دادهها
│ └── helpers.py # توابع کمکی
└── data/
├── books.json # دادههای کتابها
├── members.json # دادههای اعضا
└── loans.json # دادههای امانتها
مدل کتاب (Book)
models/book.py
from datetime import datetime
import re
class Book:
def __init__(self, isbn, title, author, publisher, year, copies=1):
self.isbn = self._validate_isbn(isbn)
self.title = title.strip()
self.author = author.strip()
self.publisher = publisher.strip()
self.year = self._validate_year(year)
self.copies = max(1, copies)
self.available_copies = copies
self.created_at = datetime.now().isoformat()
def _validate_isbn(self, isbn):
"""اعتبارسنجی شابک کتاب"""
isbn_pattern = r'^\d{10}(\d{3})?$'
clean_isbn = re.sub(r'[^\d]', '', isbn)
if not re.match(isbn_pattern, clean_isbn):
raise ValueError("شابک نامعتبر است")
return clean_isbn
def _validate_year(self, year):
"""اعتبارسنجی سال انتشار"""
current_year = datetime.now().year
if not (1000 <= year <= current_year):
raise ValueError(f"سال انتشار باید بین 1000 تا {current_year} باشد")
return year
def is_available(self):
"""بررسی در دسترس بودن کتاب"""
return self.available_copies > 0
def borrow(self):
"""امانت دادن کتاب"""
if not self.is_available():
raise ValueError("کتاب در دسترس نیست")
self.available_copies -= 1
def return_book(self):
"""بازگشت کتاب"""
if self.available_copies >= self.copies:
raise ValueError("تمام نسخههای کتاب موجود است")
self.available_copies += 1
def to_dict(self):
"""تبدیل به دیکشنری برای ذخیره در JSON"""
return {
'isbn': self.isbn,
'title': self.title,
'author': self.author,
'publisher': self.publisher,
'year': self.year,
'copies': self.copies,
'available_copies': self.available_copies,
'created_at': self.created_at
}
@classmethod
def from_dict(cls, data):
"""ساخت شیء از دیکشنری"""
book = cls(
data['isbn'], data['title'], data['author'],
data['publisher'], data['year'], data['copies']
)
book.available_copies = data.get('available_copies', data['copies'])
book.created_at = data.get('created_at', datetime.now().isoformat())
return book
def __str__(self):
return f"{self.title} - {self.author} ({self.year})"
def __repr__(self):
return f"Book(isbn='{self.isbn}', title='{self.title}')"
مدل عضو (Member)
models/member.py
from datetime import datetime
import re
class Member:
def __init__(self, member_id, name, email, phone, address=""):
self.member_id = str(member_id)
self.name = name.strip()
self.email = self._validate_email(email)
self.phone = self._validate_phone(phone)
self.address = address.strip()
self.join_date = datetime.now().isoformat()
self.borrowed_books = [] # لیست ISBN کتابهای امانت گرفته شده
self.is_active = True
def _validate_email(self, email):
"""اعتبارسنجی ایمیل"""
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, email):
raise ValueError("ایمیل نامعتبر است")
return email.lower()
def _validate_phone(self, phone):
"""اعتبارسنجی شماره تلفن"""
phone_pattern = r'^09\d{9}$'
clean_phone = re.sub(r'[^\d]', '', phone)
if not re.match(phone_pattern, clean_phone):
raise ValueError("شماره تلفن نامعتبر است (باید با 09 شروع شود)")
return clean_phone
def can_borrow(self, max_books=3):
"""بررسی امکان امانت گرفتن کتاب جدید"""
return len(self.borrowed_books) < max_books and self.is_active
def borrow_book(self, isbn):
"""امانت گرفتن کتاب"""
if not self.can_borrow():
raise ValueError("امکان امانت گرفتن کتاب جدید وجود ندارد")
if isbn in self.borrowed_books:
raise ValueError("این کتاب قبلاً امانت گرفته شده")
self.borrowed_books.append(isbn)
def return_book(self, isbn):
"""بازگشت کتاب"""
if isbn not in self.borrowed_books:
raise ValueError("این کتاب توسط این عضو امانت گرفته نشده")
self.borrowed_books.remove(isbn)
def deactivate(self):
"""غیرفعال کردن عضویت"""
if self.borrowed_books:
raise ValueError("ابتدا تمام کتابهای امانتی را بازگردانید")
self.is_active = False
def to_dict(self):
"""تبدیل به دیکشنری"""
return {
'member_id': self.member_id,
'name': self.name,
'email': self.email,
'phone': self.phone,
'address': self.address,
'join_date': self.join_date,
'borrowed_books': self.borrowed_books,
'is_active': self.is_active
}
@classmethod
def from_dict(cls, data):
"""ساخت شیء از دیکشنری"""
member = cls(
data['member_id'], data['name'], data['email'],
data['phone'], data.get('address', '')
)
member.join_date = data.get('join_date', datetime.now().isoformat())
member.borrowed_books = data.get('borrowed_books', [])
member.is_active = data.get('is_active', True)
return member
def __str__(self):
return f"{self.name} ({self.member_id})"
مدیر کتابخانه (Library Manager)
managers/library_manager.py
from datetime import datetime, timedelta
from models.book import Book
from models.member import Member
from models.loan import Loan
from managers.file_manager import FileManager
from utils.validators import validate_search_query
class LibraryManager:
def __init__(self, data_dir="data"):
self.file_manager = FileManager(data_dir)
self.books = self._load_books()
self.members = self._load_members()
self.loans = self._load_loans()
def _load_books(self):
"""بارگذاری کتابها از فایل"""
data = self.file_manager.load_books()
return {book['isbn']: Book.from_dict(book) for book in data}
def _load_members(self):
"""بارگذاری اعضا از فایل"""
data = self.file_manager.load_members()
return {member['member_id']: Member.from_dict(member) for member in data}
def _load_loans(self):
"""بارگذاری امانتها از فایل"""
data = self.file_manager.load_loans()
return [Loan.from_dict(loan) for loan in data]
def save_all_data(self):
"""ذخیره تمام دادهها"""
try:
# ذخیره کتابها
books_data = [book.to_dict() for book in self.books.values()]
self.file_manager.save_books(books_data)
# ذخیره اعضا
members_data = [member.to_dict() for member in self.members.values()]
self.file_manager.save_members(members_data)
# ذخیره امانتها
loans_data = [loan.to_dict() for loan in self.loans]
self.file_manager.save_loans(loans_data)
print("✅ تمام دادهها با موفقیت ذخیره شدند")
except Exception as e:
print(f"❌ خطا در ذخیره دادهها: {e}")
# مدیریت کتابها
def add_book(self, isbn, title, author, publisher, year, copies=1):
"""افزودن کتاب جدید"""
try:
if isbn in self.books:
# اگر کتاب موجود است، تعداد نسخهها را افزایش دهیم
self.books[isbn].copies += copies
self.books[isbn].available_copies += copies
print(f"✅ تعداد نسخههای کتاب '{title}' افزایش یافت")
else:
book = Book(isbn, title, author, publisher, year, copies)
self.books[isbn] = book
print(f"✅ کتاب '{title}' با موفقیت اضافه شد")
self.save_all_data()
except ValueError as e:
print(f"❌ خطا: {e}")
def search_books(self, query, search_type="title"):
"""جستجوی کتابها"""
if not validate_search_query(query):
return []
query = query.lower().strip()
results = []
for book in self.books.values():
if search_type == "title" and query in book.title.lower():
results.append(book)
elif search_type == "author" and query in book.author.lower():
results.append(book)
elif search_type == "isbn" and query in book.isbn:
results.append(book)
return results
def get_book_info(self, isbn):
"""دریافت اطلاعات کتاب"""
return self.books.get(isbn)
# مدیریت اعضا
def add_member(self, member_id, name, email, phone, address=""):
"""افزودن عضو جدید"""
try:
if member_id in self.members:
print(f"❌ عضوی با شناسه {member_id} قبلاً ثبت شده")
return False
member = Member(member_id, name, email, phone, address)
self.members[member_id] = member
print(f"✅ عضو '{name}' با موفقیت اضافه شد")
self.save_all_data()
return True
except ValueError as e:
print(f"❌ خطا: {e}")
return False
def get_member_info(self, member_id):
"""دریافت اطلاعات عضو"""
return self.members.get(str(member_id))
# مدیریت امانتها
def borrow_book(self, member_id, isbn):
"""امانت دادن کتاب"""
try:
member = self.get_member_info(member_id)
book = self.get_book_info(isbn)
if not member:
print(f"❌ عضوی با شناسه {member_id} یافت نشد")
return False
if not book:
print(f"❌ کتابی با شابک {isbn} یافت نشد")
return False
# بررسی امکان امانت
if not member.can_borrow():
print("❌ این عضو نمیتواند کتاب جدید امانت بگیرد")
return False
if not book.is_available():
print("❌ این کتاب در حال حاضر در دسترس نیست")
return False
# انجام امانت
book.borrow()
member.borrow_book(isbn)
# ثبت امانت
loan = Loan(member_id, isbn)
self.loans.append(loan)
print(f"✅ کتاب '{book.title}' به '{member.name}' امانت داده شد")
self.save_all_data()
return True
except Exception as e:
print(f"❌ خطا در امانت: {e}")
return False
def return_book(self, member_id, isbn):
"""بازگشت کتاب"""
try:
member = self.get_member_info(member_id)
book = self.get_book_info(isbn)
if not member or not book:
print("❌ اطلاعات عضو یا کتاب یافت نشد")
return False
# پیدا کردن امانت فعال
active_loan = None
for loan in self.loans:
if (loan.member_id == str(member_id) and
loan.isbn == isbn and not loan.is_returned):
active_loan = loan
break
if not active_loan:
print("❌ امانت فعالی برای این کتاب و عضو یافت نشد")
return False
# بازگشت کتاب
book.return_book()
member.return_book(isbn)
active_loan.return_book()
print(f"✅ کتاب '{book.title}' با موفقیت بازگردانده شد")
self.save_all_data()
return True
except Exception as e:
print(f"❌ خطا در بازگشت: {e}")
return False
def get_overdue_loans(self, days=14):
"""دریافت امانتهای معوقه"""
overdue_date = datetime.now() - timedelta(days=days)
overdue_loans = []
for loan in self.loans:
if (not loan.is_returned and
datetime.fromisoformat(loan.loan_date) < overdue_date):
overdue_loans.append(loan)
return overdue_loans
def generate_report(self):
"""تولید گزارش کلی کتابخانه"""
total_books = len(self.books)
total_copies = sum(book.copies for book in self.books.values())
available_copies = sum(book.available_copies for book in self.books.values())
borrowed_copies = total_copies - available_copies
total_members = len(self.members)
active_members = sum(1 for member in self.members.values() if member.is_active)
total_loans = len(self.loans)
active_loans = sum(1 for loan in self.loans if not loan.is_returned)
overdue_loans = len(self.get_overdue_loans())
report = f"""
📊 گزارش کلی کتابخانه
{'='*30}
📚 کتابها:
- تعداد کل کتابها: {total_books}
- تعداد کل نسخهها: {total_copies}
- نسخههای موجود: {available_copies}
- نسخههای امانتی: {borrowed_copies}
👥 اعضا:
- تعداد کل اعضا: {total_members}
- اعضای فعال: {active_members}
📋 امانتها:
- تعداد کل امانتها: {total_loans}
- امانتهای فعال: {active_loans}
- امانتهای معوقه: {overdue_loans}
"""
return report
برنامه اصلی
main.py
from managers.library_manager import LibraryManager
from utils.helpers import clear_screen, get_user_input, show_menu
def main():
"""تابع اصلی برنامه"""
library = LibraryManager()
print("🏛️ خوش آمدید به سیستم مدیریت کتابخانه")
print("="*50)
while True:
try:
clear_screen()
choice = show_main_menu()
if choice == '1':
book_management_menu(library)
elif choice == '2':
member_management_menu(library)
elif choice == '3':
loan_management_menu(library)
elif choice == '4':
reports_menu(library)
elif choice == '5':
print("👋 خداحافظ!")
break
else:
print("❌ گزینه نامعتبر")
input("برای ادامه Enter بزنید...")
except KeyboardInterrupt:
print("\n👋 برنامه متوقف شد")
break
except Exception as e:
print(f"❌ خطای غیرمنتظره: {e}")
input("برای ادامه Enter بزنید...")
def show_main_menu():
"""نمایش منوی اصلی"""
menu_options = [
"📚 مدیریت کتابها",
"👥 مدیریت اعضا",
"📋 مدیریت امانتها",
"📊 گزارشها",
"🚪 خروج"
]
print("\n🏛️ منوی اصلی سیستم مدیریت کتابخانه")
print("="*40)
for i, option in enumerate(menu_options, 1):
print(f"{i}. {option}")
return input("\nانتخاب شما: ").strip()
def book_management_menu(library):
"""منوی مدیریت کتابها"""
while True:
clear_screen()
print("📚 مدیریت کتابها")
print("="*20)
print("1. افزودن کتاب")
print("2. جستجوی کتاب")
print("3. مشاهده اطلاعات کتاب")
print("4. بازگشت به منوی اصلی")
choice = input("\nانتخاب شما: ").strip()
if choice == '1':
add_book_interface(library)
elif choice == '2':
search_books_interface(library)
elif choice == '3':
view_book_interface(library)
elif choice == '4':
break
else:
print("❌ گزینه نامعتبر")
input("برای ادامه Enter بزنید...")
def add_book_interface(library):
"""رابط افزودن کتاب"""
print("\n➕ افزودن کتاب جدید")
print("-"*20)
try:
isbn = input("شابک کتاب: ").strip()
title = input("عنوان کتاب: ").strip()
author = input("نویسنده: ").strip()
publisher = input("ناشر: ").strip()
year = int(input("سال انتشار: "))
copies = int(input("تعداد نسخهها (پیشفرض: 1): ") or "1")
library.add_book(isbn, title, author, publisher, year, copies)
except ValueError as e:
print(f"❌ خطا در ورودی: {e}")
except Exception as e:
print(f"❌ خطای غیرمنتظره: {e}")
input("\nبرای ادامه Enter بزنید...")
def search_books_interface(library):
"""رابط جستجوی کتابها"""
print("\n🔍 جستجوی کتاب")
print("-"*15)
search_type = input("نوع جستجو (title/author/isbn): ").strip().lower()
if search_type not in ['title', 'author', 'isbn']:
search_type = 'title'
query = input(f"جستجو بر اساس {search_type}: ").strip()
if not query:
print("❌ متن جستجو نمیتواند خالی باشد")
input("برای ادامه Enter بزنید...")
return
results = library.search_books(query, search_type)
if results:
print(f"\n✅ {len(results)} کتاب یافت شد:")
print("-"*50)
for i, book in enumerate(results, 1):
print(f"{i}. {book.title} - {book.author}")
print(f" شابک: {book.isbn} | موجود: {book.available_copies}/{book.copies}")
print()
else:
print("❌ کتابی یافت نشد")
input("برای ادامه Enter بزنید...")
if __name__ == "__main__":
main()
تمرین عملی
تمرین 1: گسترش سیستم
ویژگیهای زیر را به سیستم اضافه کنید:
- • سیستم رزرو کتاب
- • مدیریت جریمه برای تأخیر
- • دستهبندی کتابها
- • سیستم امتیازدهی به کتابها
راهحل تمرین 1:
# اضافه کردن کلاس رزرو
class Reservation:
def __init__(self, member_id, isbn):
self.member_id = str(member_id)
self.isbn = isbn
self.reservation_date = datetime.now().isoformat()
self.is_active = True
self.expiry_date = (datetime.now() + timedelta(days=3)).isoformat()
def is_expired(self):
return datetime.now() > datetime.fromisoformat(self.expiry_date)
# اضافه کردن به LibraryManager
def reserve_book(self, member_id, isbn):
"""رزرو کتاب"""
member = self.get_member_info(member_id)
book = self.get_book_info(isbn)
if not member or not book:
return False
if book.is_available():
print("کتاب در دسترس است، میتوانید مستقیماً امانت بگیرید")
return False
# بررسی رزرو قبلی
for reservation in self.reservations:
if (reservation.member_id == str(member_id) and
reservation.isbn == isbn and reservation.is_active):
print("شما قبلاً این کتاب را رزرو کردهاید")
return False
reservation = Reservation(member_id, isbn)
self.reservations.append(reservation)
print(f"کتاب '{book.title}' برای شما رزرو شد")
return True
تمرین 2: رابط گرافیکی
با استفاده از tkinter یک رابط گرافیکی ساده برای سیستم بسازید.
راهحل تمرین 2:
import tkinter as tk
from tkinter import ttk, messagebox
from managers.library_manager import LibraryManager
class LibraryGUI:
def __init__(self, root):
self.root = root
self.root.title("سیستم مدیریت کتابخانه")
self.root.geometry("800x600")
self.library = LibraryManager()
self.create_widgets()
def create_widgets(self):
# ایجاد تبها
notebook = ttk.Notebook(self.root)
notebook.pack(fill='both', expand=True, padx=10, pady=10)
# تب کتابها
books_frame = ttk.Frame(notebook)
notebook.add(books_frame, text='کتابها')
self.create_books_tab(books_frame)
# تب اعضا
members_frame = ttk.Frame(notebook)
notebook.add(members_frame, text='اعضا')
self.create_members_tab(members_frame)
def create_books_tab(self, parent):
# فرم افزودن کتاب
add_frame = ttk.LabelFrame(parent, text="افزودن کتاب")
add_frame.pack(fill='x', padx=5, pady=5)
ttk.Label(add_frame, text="شابک:").grid(row=0, column=0, sticky='w')
self.isbn_entry = ttk.Entry(add_frame)
self.isbn_entry.grid(row=0, column=1, sticky='ew')
ttk.Label(add_frame, text="عنوان:").grid(row=1, column=0, sticky='w')
self.title_entry = ttk.Entry(add_frame)
self.title_entry.grid(row=1, column=1, sticky='ew')
ttk.Button(add_frame, text="افزودن",
command=self.add_book).grid(row=2, column=1, sticky='e')
add_frame.columnconfigure(1, weight=1)
def add_book(self):
isbn = self.isbn_entry.get().strip()
title = self.title_entry.get().strip()
if not isbn or not title:
messagebox.showerror("خطا", "لطفاً تمام فیلدها را پر کنید")
return
try:
# فرض میکنیم سایر فیلدها را هم دریافت کردهایم
self.library.add_book(isbn, title, "نویسنده", "ناشر", 2023)
messagebox.showinfo("موفقیت", "کتاب با موفقیت اضافه شد")
self.clear_book_entries()
except Exception as e:
messagebox.showerror("خطا", str(e))
def clear_book_entries(self):
self.isbn_entry.delete(0, tk.END)
self.title_entry.delete(0, tk.END)
if __name__ == "__main__":
root = tk.Tk()
app = LibraryGUI(root)
root.mainloop()
خلاصه پروژه
مفاهیم استفاده شده:
- کلاسها و شیءگرایی
- مدیریت فایلها و JSON
- Exception Handling
- Regular Expressions
- تاریخ و زمان
ویژگیهای پیادهسازی شده:
- مدیریت کامل کتابها
- مدیریت اعضای کتابخانه
- سیستم امانت و بازگشت
- جستجوی پیشرفته
- گزارشگیری و آمار
🎉 تبریک! شما با موفقیت یک سیستم مدیریت کتابخانه کامل با پایتون ساختید. این پروژه نشاندهنده تسلط شما بر مفاهیم مختلف برنامهنویسی پایتون است.