در دنیای حرفه‌ای توسعه بک‌اِند، جستجو در پایگاه داده هرگز به یک تساوی ساده (=) ختم نمی‌شود. به عنوان یک معمار نرم‌افزار، باید بدانید که کارایی (Performance) و دقت در فیلترینگ، مرز بین یک اپلیکیشن معمولی و یک سیستم مقیاس‌پذیر است. مفهوم Field Lookups در Django ORM ابزاری است که به شما اجازه می‌دهد پرس‌وجوهای SQL پیچیده را با نوشتاری ساده و پایتونیک پیاده‌سازی کنید.

در دنیای حرفه‌ای توسعه بک‌اِند، جستجو در پایگاه داده هرگز به یک تساوی ساده (=) ختم نمی‌شود. به عنوان یک معمار نرم‌افزار، باید بدانید که کارایی (Performance) و دقت در فیلترینگ، مرز بین یک اپلیکیشن معمولی و یک سیستم مقیاس‌پذیر است. مفهوم Field Lookups در Django ORM ابزاری است که به شما اجازه می‌دهد پرس‌وجوهای SQL پیچیده را با نوشتاری ساده و پایتونیک پیاده‌سازی کنید.

۱. مفهوم‌شناسی و زیربنای Field Lookups

ساختار فیلترینگ در جنگو بر پایه یک قرارداد هوشمندانه بنا شده است. وقتی از متد .filter() استفاده می‌کنید، در واقع دارید به ORM می‌گویید که چگونه بند WHERE را در کوئری SQL بنویسد.

کالبدشکافی ساختار:Model.objects.filter(field__lookup=value)

Model: کلاسی که مدل‌سازی جدول دیتابیس را بر عهده دارد.

objects: منیجر پیش‌فرض که درگاه ورود ما به دنیای پرس‌وجوهاست.

field: نام فیلدی که می‌خواهید روی آن فیلتر بزنید.

دو زیرخط (__): این یک قرارداد حیاتی است. جنگو از دو زیرخط استفاده می‌کند تا “نام فیلد” را از “نوع عملیات” جدا کند. چرا دو تا؟ چون ممکن است خود فیلد شما دارای زیرخط باشد (مثل first_name)؛ استفاده از دو زیرخط تداخل نام‌گذاری را از بین می‌برد و به پایتون می‌فهماند که بخش دوم، یک دستور ویژه (Lookup) است.

lookup: منطق مقایسه (مثلاً “بزرگتر از”).

value: مقداری که قرار است با فیلد مقایسه شود.

حالا که با ساختار اولیه آشنا شدیم، بیایید ببینیم چطور می‌توانیم با کلمات در پایگاه داده جادو کنیم.

——————————————————————————–

۲. جستجوگر متن: کار با رشته‌ها (String Lookups)

در کار با متن، دقت در جستجو (Case-sensitivity) اهمیت بالایی دارد. جنگو به شما این قدرت را می‌دهد که انتخاب کنید آیا حروف کوچک و بزرگ در نتیجه تاثیر بگذارند یا خیر.

نام Lookup توضیح کاربردی مثال کد
exact تساوی دقیق و حساس به حروف headline__exact="Hello"
iexact تساوی دقیق (بدون حساسیت به حروف) username__iexact="Admin"
contains شامل عبارت باشد (حساس به حروف) bio__contains="Python"
icontains شامل عبارت باشد (بدون حساسیت) content__icontains="django"
startswith شروع با عبارت مشخص (حساس) code__startswith="PRO"
istartswith شروع با عبارت (بدون حساسیت) email__istartswith="info"
endswith پایان با عبارت مشخص (حساس) file_path__endswith=".pdf"
iendswith پایان با عبارت (بدون حساسیت) domain__iendswith=".COM"
regex تطابق با عبارت منظم (Regex) phone__regex=r'^\d{3}$'
iregex Regex (بدون حساسیت به حروف) slug__iregex=r'^[a-z]+$'

نکته طلایی: “قانون طلایی حرف i”در اکوسیستم جنگو، وجود حرف i در ابتدای هر Lookup (مانند icontains یا iexact) مخفف کلمه Ignore Case است. این یعنی دیتابیس در هنگام جستجو، تفاوتی بین ‘A’ و ‘a’ قائل نمی‌شود که برای بهبود تجربه کاربری در فیلدهای جستجو ضروری است.

اما جستجو همیشه محدود به کلمات نیست؛ گاهی اعداد و بازه‌ها هستند که به داده‌های ما معنا می‌دهند.

——————————————————————————–

۳. منطق ریاضی: مقایسه مقادیر و اعداد (Comparison Lookups)

عملگرهای مقایسه‌ای ستون فقرات منطق تجاری هستند. جنگو این عملگرها را از زبان ریاضی به کلمات کوتاه تبدیل کرده است.

Lookup معادل ریاضی / معنی مثال کاربردی
gt > (بزرگ‌تر از) price__gt=50000
gte >= (بزرگ‌تر یا مساوی) stock__gte=10
lt < (کوچک‌تر از) age__lt=18
lte <= (کوچک‌تر یا مساوی) score__lte=100
range حضور در یک بازه (بسته) id__range=(10, 50)
in عضو یک مجموعه بودن status__in=["active", "pending"]
isnull بررسی تهی بودن (NULL) deleted_at__isnull=True

تحلیل عمیق: تفاوت کاربردی range و inاز دیدگاه یک برنامه نویس ارشد، انتخاب بین این دو به نوع داده و سناریو بستگی دارد:

range: برای مقادیر پیوسته استفاده می‌شود و معمولاً یک تاپل (Tuple) شامل دو مقدار (شروع و پایان) دریافت می‌کند. SQL تولید شده از آن از دستور BETWEEN استفاده می‌کند.

in: برای مقادیر گسسته و نامنظم استفاده می‌شود و یک لیست (List) از گزینه‌های مختلف را می‌پذیرد. این لوک‌آپ برای زمانی که می‌خواهید بدانید یک مقدار در میان چندین گزینه خاص هست یا نه، بهترین گزینه است.

دقیق‌ترین نوع فیلترینگ زمانی رخ می‌دهد که بخواهیم در ابعاد زمان و تاریخ سفر کنیم.

——————————————————————————–

۴. جراحی زمان: فیلترهای تاریخ و ساعت (Date & Time Lookups)

فیلدهای DateTimeField حاوی اطلاعات زیادی هستند. گاهی نیاز داریم فقط بر اساس سال یا حتی ساعت خاصی فیلتر کنیم.

جدول ۱: فیلترهای تاریخ و اجزای تقویمی

Lookup توضیح مثال
date تبدیل datetime به تاریخ ساده created_at__date="2025-05-12"
year فیلتر بر اساس سال birth_date__year=1995
iso_year سال بر اساس استاندارد ISO 8601 created_at__iso_year=2024
month فیلتر بر اساس ماه (۱ تا ۱۲) joining_date__month=12
day روزِ ماه (۱ تا ۳۱) event__day=25
week شماره هفته در سال (۱ تا ۵۳) report__week=42
quarter فصل سال (۱ تا ۴) sales__quarter=3

جدول ۲: فیلترهای زمان و روزهای هفته

Lookup توضیح مقدار عددی (نکته مهم)
week_day روز هفته (استاندارد دیتابیس) 1=Sunday (یکشنبه) تا 7
iso_week_day روز هفته (استاندارد ISO) 1=Monday (دوشنبه) تا 7
hour استخراج ساعت (۰ تا ۲۳) log__hour=14
minute استخراج دقیقه (۰ تا ۵۹) task__minute=30
second استخراج ثانیه (۰ تا ۵۹) tick__second=0
time فیلتر بر اساس زمان (بدون تاریخ) start__time="14:30:00"

——————————————————————————–

۵. خلاصه مدیریتی و نقشه ذهنی مرور سریع

برای تسلط در زمان کدنویسی، این “جعبه ابزار سریع” را همیشه دم دست داشته باشید:

فرمول نهایی قدرت:

# Field Name + Double Underscore + Lookup Type
field__lookup=value

چک‌لیست نهایی برای مرور:

• [ ] کستینگ (Casting): لوک‌آپ‌هایی مثل date یا time در واقع نوع داده را برای مقایسه موقتاً تغییر می‌دهند تا فقط بخشی از datetime سنجیده شود.

• [ ] قاعده i: همیشه یادتان باشد i یعنی Case-insensitive؛ اگر جستجوی کاربر دارید، حتماً از نسخه i دار استفاده کنید.

• [ ] ریاضیات ساده: مخفف‌های gt (Greater Than) و lt (Less Than) را مانند نمادهای ریاضی تصور کنید.

• [ ] تمایز روز هفته: در week_day عدد ۱ یکشنبه است، اما در iso_week_day عدد ۱ دوشنبه است.

مقایسه پرکاربردترین‌ها:

قابلیت contains icontains
حساسیت به حروف حساس (Ali != ali) غیرحساس (Ali == ali)
بهترین مورد استفاده فیلدهای سیستمی و Case-sensitive فیلدهای جستجوی کاربر و متون عمومی

نکته پایانی: استفاده از دو زیرخط (__) در جنگو یک اجبار برای تفکیک منطقی است. اگر از یک زیرخط استفاده کنید، ORM به دنبال فیلدی با آن نام می‌گردد و با خطای FieldError مواجه خواهید شد. همیشه پل ارتباطی خود را با دو زیرخط بسازید!

Discuss This Article with the Community

Have a question, a different approach, or something you built after reading this? Share it on the forum or join the Discord, we'd love to hear from you.