🔍 ধাপ ১: Search ফিচার যোগ করুন
ফাইল: app/apps/students/routes.py
আপনার বিদ্যমান get_all_students ফাংশনকে এভাবে পরিবর্তন করুন:
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from app.db.session import get_db
from . import models, schemas
router = APIRouter(prefix="/students", tags=["Students"])
# ১. Create (তৈরি করা) - এটি আগের মতোই থাকবে
@router.post("/", response_model=schemas.StudentResponse)
def create_student(student: schemas.StudentCreate, db: Session = Depends(get_db)):
"""নতুন স্টুডেন্ট তৈরি করা"""
db_student = models.Student(**student.dict())
db.add(db_student)
db.commit()
db.refresh(db_student)
return db_student
# ২. Read All with Search (সার্চ সহ সব দেখা) - নতুন ভার্সন
@router.get("/", response_model=List[schemas.StudentResponse])
def get_all_students(
db: Session = Depends(get_db),
search: Optional[str] = Query(None, description="নাম বা ইমেইল দিয়ে সার্চ করুন")
):
"""
সব স্টুডেন্ট দেখা (সার্চ সহ)
Query Parameters:
- search: নাম বা ইমেইল দিয়ে সার্চ করুন (অপশনাল)
উদাহরণ:
- GET /students/ - সব স্টুডেন্ট
- GET /students/?search=আহমেদ - নাম দিয়ে সার্চ
- GET /students/?search=ahmed@example.com - ইমেইল দিয়ে সার্চ
"""
query = db.query(models.Student)
# যদি সার্চ টার্ম থাকে তাহলে ফিল্টার করুন
if search:
# নাম বা ইমেইল দিয়ে সার্চ করুন (কেস-ইনসেনসিটিভ)
query = query.filter(
(models.Student.name.ilike(f"%{search}%")) |
(models.Student.email.ilike(f"%{search}%"))
)
return query.all()
# ৩. Read One (একটি দেখা) - এটি আগের মতোই থাকবে
@router.get("/{student_id}", response_model=schemas.StudentResponse)
def get_student(student_id: int, db: Session = Depends(get_db)):
"""নির্দিষ্ট স্টুডেন্ট দেখা"""
db_student = db.query(models.Student).filter(models.Student.id == student_id).first()
if not db_student:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
# ৪. Update (পরিবর্তন করা) - এটি আগের মতোই থাকবে
@router.put("/{student_id}", response_model=schemas.StudentResponse)
def update_student(student_id: int, student_data: schemas.StudentUpdate, db: Session = Depends(get_db)):
"""স্টুডেন্ট আপডেট করা"""
db_student = db.query(models.Student).filter(models.Student.id == student_id).first()
if not db_student:
raise HTTPException(status_code=404, detail="Student not found")
updated_info = student_data.dict(exclude_unset=True)
for key, value in updated_info.items():
setattr(db_student, key, value)
db.commit()
db.refresh(db_student)
return db_student
# ৫. Delete (মুছে ফেলা) - এটি আগের মতোই থাকবে
@router.delete("/{student_id}")
def delete_student(student_id: int, db: Session = Depends(get_db)):
"""স্টুডেন্ট মুছে ফেলা"""
db_student = db.query(models.Student).filter(models.Student.id == student_id).first()
if not db_student:
raise HTTPException(status_code=404, detail="Student not found")
db.delete(db_student)
db.commit()
return {"message": "Successfully Deleted"}
📝 বিস্তারিত আলোচনা:
Query(None, description="..."): এটি একটি Query Parameter। URL এ ?search=value এর মাধ্যমে পাঠানো হয়।
Optional[str]: এই প্যারামিটার অপশনাল। না পাঠালেও চলবে।
ilike(): Case-insensitive LIKE অপারেটর। বড় ছোট হরফ নিয়ে চিন্তা করে না।
f"%{search}%": সার্চ টার্মের আগে এবং পরে % যোগ করে। এটি যেকোনো জায়গায় ম্যাচ করে।
| (OR অপারেটর): নাম বা ইমেইল যেকোনো একটিতে ম্যাচ করলে রেজাল্ট দেবে।
📄 ধাপ ২: Pagination ফিচার যোগ করুন
ফাইল: app/apps/students/schemas.py
প্রথমে Pagination এর জন্য একটি নতুন স্কিমা যোগ করুন:
from pydantic import BaseModel, EmailStr
from typing import Optional, List
# কমন ডাটা
class StudentBase(BaseModel):
name: str
email: EmailStr
age: int
# ইনপুট নেওয়ার জন্য (Create)
class StudentCreate(StudentBase):
pass
# আপডেট করার জন্য
class StudentUpdate(BaseModel):
name: Optional[str] = None
email: Optional[EmailStr] = None
age: Optional[int] = None
# ডাটা দেখানোর জন্য (Response)
class StudentResponse(StudentBase):
id: int
class Config:
from_attributes = True
# Pagination এর জন্য নতুন স্কিমা
class PaginatedStudentResponse(BaseModel):
"""Pagination সহ স্টুডেন্ট লিস্ট"""
total: int # মোট স্টুডেন্ট সংখ্যা
page: int # বর্তমান পেজ
page_size: int # প্রতি পেজে কতটি আইটেম
total_pages: int # মোট পেজ সংখ্যা
data: List[StudentResponse] # স্টুডেন্ট লিস্ট
ফাইল: app/apps/students/routes.py
এখন Pagination সহ একটি নতুন এন্ডপয়েন্ট যোগ করুন:
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from math import ceil
from app.db.session import get_db
from . import models, schemas
router = APIRouter(prefix="/students", tags=["Students"])
# ... আগের সব ফাংশন এখানে থাকবে ...
# নতুন এন্ডপয়েন্ট: Pagination সহ সার্চ
@router.get("/search/paginated", response_model=schemas.PaginatedStudentResponse)
def search_students_paginated(
db: Session = Depends(get_db),
search: Optional[str] = Query(None, description="নাম বা ইমেইল দিয়ে সার্চ করুন"),
page: int = Query(1, ge=1, description="পেজ নম্বর (১ থেকে শুরু)"),
page_size: int = Query(10, ge=1, le=100, description="প্রতি পেজে কতটি আইটেম (১-১০০)")
):
"""
Pagination সহ স্টুডেন্ট সার্চ করুন
Query Parameters:
- search: নাম বা ইমেইল দিয়ে সার্চ করুন (অপশনাল)
- page: পেজ নম্বর (ডিফল্ট: ১)
- page_size: প্রতি পেজে কতটি আইটেম (ডিফল্ট: ১০, ম্যাক্স: ১০০)
উদাহরণ:
- GET /students/search/paginated - প্রথম পেজ (১০টি আইটেম)
- GET /students/search/paginated?page=2 - দ্বিতীয় পেজ
- GET /students/search/paginated?search=আহমেদ&page=1&page_size=5 - সার্চ সহ
"""
# বেস কোয়েরি তৈরি করুন
query = db.query(models.Student)
# যদি সার্চ টার্ম থাকে তাহলে ফিল্টার করুন
if search:
query = query.filter(
(models.Student.name.ilike(f"%{search}%")) |
(models.Student.email.ilike(f"%{search}%"))
)
# মোট রেকর্ড সংখ্যা
total = query.count()
# মোট পেজ সংখ্যা
total_pages = ceil(total / page_size)
# Offset এবং Limit ক্যালকুলেট করুন
offset = (page - 1) * page_size
# ডাটা ফেচ করুন
students = query.offset(offset).limit(page_size).all()
return {
"total": total,
"page": page,
"page_size": page_size,
"total_pages": total_pages,
"data": students
}
📝 বিস্তারিত আলোচনা:
page: int = Query(1, ge=1): পেজ নম্বর। ge=1 মানে ১ এর চেয়ে বড় বা সমান হতে হবে।
page_size: int = Query(10, ge=1, le=100): প্রতি পেজে কতটি আইটেম। le=100 মানে ১০০ এর চেয়ে বেশি হতে পারবে না।
ceil(total / page_size): মোট পেজ সংখ্যা ক্যালকুলেট করে। যেমন: ২৫ টি আইটেম এবং ১০ প্রতি পেজ = ৩ পেজ।
offset = (page - 1) * page_size: কত সংখ্যক রেকর্ড স্কিপ করবে। পেজ ২ এবং পেজ সাইজ ১০ হলে = ১০ স্কিপ করবে।
query.offset(offset).limit(page_size): নির্দিষ্ট সংখ্যক রেকর্ড স্কিপ করে বাকিটা নিয়ে আসে।
🎯 ধাপ ৩: উন্নত Search ফিচার
ফাইল: app/apps/students/routes.py
আরও উন্নত সার্চ ফিচার যোগ করুন (নির্দিষ্ট ফিল্ড দিয়ে সার্চ):
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from math import ceil
from app.db.session import get_db
from . import models, schemas
router = APIRouter(prefix="/students", tags=["Students"])
# উন্নত সার্চ এন্ডপয়েন্ট
@router.get("/advanced-search", response_model=List[schemas.StudentResponse])
def advanced_search(
db: Session = Depends(get_db),
name: Optional[str] = Query(None, description="নাম দিয়ে সার্চ"),
email: Optional[str] = Query(None, description="ইমেইল দিয়ে সার্চ"),
age_min: Optional[int] = Query(None, ge=0, description="ন্যূনতম বয়স"),
age_max: Optional[int] = Query(None, ge=0, description="সর্বোচ্চ বয়স"),
sort_by: Optional[str] = Query("id", description="সর্ট করার ফিল্ড (id, name, email, age)"),
sort_order: Optional[str] = Query("asc", description="সর্ট অর্ডার (asc, desc)")
):
"""
উন্নত সার্চ ফিচার
Query Parameters:
- name: নাম দিয়ে সার্চ
- email: ইমেইল দিয়ে সার্চ
- age_min: ন্যূনতম বয়স
- age_max: সর্বোচ্চ বয়স
- sort_by: সর্ট করার ফিল্ড
- sort_order: সর্ট অর্ডার (asc/desc)
উদাহরণ:
- GET /students/advanced-search?name=আহমেদ
- GET /students/advanced-search?age_min=18&age_max=25
- GET /students/advanced-search?sort_by=name&sort_order=desc
"""
query = db.query(models.Student)
# নাম দিয়ে ফিল্টার
if name:
query = query.filter(models.Student.name.ilike(f"%{name}%"))
# ইমেইল দিয়ে ফিল্টার
if email:
query = query.filter(models.Student.email.ilike(f"%{email}%"))
# বয়স রেঞ্জ দিয়ে ফিল্টার
if age_min is not None:
query = query.filter(models.Student.age >= age_min)
if age_max is not None:
query = query.filter(models.Student.age <= age_max)
# সর্ট করুন
if sort_by == "name":
sort_column = models.Student.name
elif sort_by == "email":
sort_column = models.Student.email
elif sort_by == "age":
sort_column = models.Student.age
else:
sort_column = models.Student.id
if sort_order == "desc":
query = query.order_by(sort_column.desc())
else:
query = query.order_by(sort_column.asc())
return query.all()
📊 ধাপ ৪: API টেস্ট করুন
সাধারণ সার্চ:
GET /students/?search=আহমেদ
রেসপন্স:
[
{
"id": 1,
"name": "আহমেদ",
"email": "ahmed@example.com",
"age": 20
}
]
Pagination সহ সার্চ:
GET /students/search/paginated?search=আহমেদ&page=1&page_size=5
রেসপন্স:
{
"total": 15,
"page": 1,
"page_size": 5,
"total_pages": 3,
"data": [
{
"id": 1,
"name": "আহমেদ",
"email": "ahmed@example.com",
"age": 20
},
{
"id": 2,
"name": "আহমেদ আলী",
"email": "ahmed.ali@example.com",
"age": 21
}
]
}
উন্নত সার্চ:
GET /students/advanced-search?age_min=18&age_max=25&sort_by=name&sort_order=asc
রেসপন্স:
[
{
"id": 2,
"name": "আহমেদ আলী",
"email": "ahmed.ali@example.com",
"age": 21
},
{
"id": 1,
"name": "আহমেদ",
"email": "ahmed@example.com",
"age": 20
}
]
🔧 ধাপ ৫: ফ্রন্টএন্ড থেকে কীভাবে কল করবেন
JavaScript/Fetch উদাহরণ:
// সাধারণ সার্চ
async function searchStudents(searchTerm) {
const response = await fetch(`/students/?search=${searchTerm}`);
const data = await response.json();
console.log(data);
}
// Pagination সহ সার্চ
async function searchWithPagination(searchTerm, page, pageSize) {
const response = await fetch(
`/students/search/paginated?search=${searchTerm}&page=${page}&page_size=${pageSize}`
);
const data = await response.json();
console.log(data);
}
// উন্নত সার্চ
async function advancedSearch(ageMin, ageMax, sortBy) {
const response = await fetch(
`/students/advanced-search?age_min=${ageMin}&age_max=${ageMax}&sort_by=${sortBy}`
);
const data = await response.json();
console.log(data);
}
Python/Requests উদাহরণ:
import requests
# সাধারণ সার্চ
response = requests.get("http://localhost:8000/students/", params={"search": "আহমেদ"})
print(response.json())
# Pagination সহ সার্চ
response = requests.get(
"http://localhost:8000/students/search/paginated",
params={"search": "আহমেদ", "page": 1, "page_size": 5}
)
print(response.json())
# উন্নত সার্চ
response = requests.get(
"http://localhost:8000/students/advanced-search",
params={"age_min": 18, "age_max": 25, "sort_by": "name"}
)
print(response.json())
⚡ পারফরম্যান্স অপটিমাইজেশন
১. ডাটাবেস ইন্ডেক্স যোগ করুন
ফাইল: app/apps/students/models.py
from sqlalchemy import Column, Integer, String, Index
from app.db.session import Base
class Student(Base):
__tablename__ = "students"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True) # সার্চের জন্য ইন্ডেক্স
email = Column(String, unique=True, index=True)
age = Column(Integer, index=True) # ফিল্টারের জন্য ইন্ডেক্স
# কম্পোজিট ইন্ডেক্স (একাধিক কলাম)
__table_args__ = (
Index('idx_name_email', 'name', 'email'),
)
২. Limit যোগ করুন
সার্চ রেজাল্ট খুব বেশি হলে সীমিত করুন:
@router.get("/", response_model=List[schemas.StudentResponse])
def get_all_students(
db: Session = Depends(get_db),
search: Optional[str] = Query(None),
limit: int = Query(100, le=1000) # ম্যাক্স ১০০০
):
query = db.query(models.Student)
if search:
query = query.filter(
(models.Student.name.ilike(f"%{search}%")) |
(models.Student.email.ilike(f"%{search}%"))
)
return query.limit(limit).all()
⚠️ সাধারণ সমস্যা এবং সমাধান
সমস্যা ১: সার্চ খুব ধীর
কারণ: ইন্ডেক্স নেই বা ডাটা খুব বেশি।
সমাধান:
- ডাটাবেস ইন্ডেক্স যোগ করুন
- Pagination ব্যবহার করুন
- LIMIT যোগ করুন
সমস্যা ২: “Invalid page number”
কারণ: পেজ নম্বর ০ বা নেগেটিভ।
সমাধান: ge=1 ভ্যালিডেশন ব্যবহার করুন (ইতিমধ্যে করা আছে)।
সমস্যা ৩: সার্চ কেস-সেনসিটিভ
কারণ: like() ব্যবহার করছেন ilike() এর পরিবর্তে।
সমাধান: সবসময় ilike() ব্যবহার করুন।
📋 API এন্ডপয়েন্ট সারসংক্ষেপ
| এন্ডপয়েন্ট | মেথড | কাজ |
|---|---|---|
/students/ | GET | সাধারণ সার্চ সহ সব দেখা |
/students/search/paginated | GET | Pagination সহ সার্চ |
/students/advanced-search | GET | উন্নত সার্চ (ফিল্ড নির্দিষ্ট) |
/students/ | POST | নতুন স্টুডেন্ট তৈরি |
/students/{id} | GET | একটি স্টুডেন্ট দেখা |
/students/{id} | PUT | স্টুডেন্ট আপডেট |
/students/{id} | DELETE | স্টুডেন্ট মুছে ফেলা |
🎯 পরবর্তী ধাপ
এখন আপনার কাছে সম্পূর্ণ Search এবং Pagination সিস্টেম আছে। আপনি যা করতে পারেন:
- ফিল্টারিং যোগ করুন – আরও উন্নত ফিল্টার
- সর্টিং অপশন বাড়ান – একাধিক ফিল্ড দিয়ে সর্ট
- এক্সপোর্ট ফিচার যোগ করুন – CSV/Excel এ এক্সপোর্ট
- ক্যাশিং যোগ করুন – রেডিস দিয়ে পারফরম্যান্স বাড়ান
📚 রেফারেন্স
আপনি চাইলে আমি এটাকে WordPress/Gutenberg-friendly ব্লক ফরম্যাটেও সাজিয়ে দিতে পারি।