در دنیای حرفهای توسعه بکاِند، جستجو در پایگاه داده هرگز به یک تساوی ساده (=) ختم نمیشود. به عنوان یک معمار نرمافزار، باید بدانید که کارایی (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.