در این قسمت سعی بر آن داریم تا عملگرهای اصلی که در SELECT نوشته میشود را در Django بنویسیم. سعی بر آن است تا با مثالهایی بتوان سرعت بالای کار با این ORM را بررسی کرد.
سعی شده تا لیستی از عملگرهای WHERE بررسی شوند.
برای کار با عملگرها در ابتدا نیاز است مثالهای کوچکی برای خود SELECT زده شود.
مثالهای ساده:
برنامهنویس نیاز دارد در حین کار با ORM برای دیباگ یکبار query ی که run میشود را ببیند تا با خروجی مقایسه کند. بدین منظور متغیر query به شکل زیر تهیه شده است:
1 2 |
q = EmployeePayTbl.objects.all() print(q.query) |
خروجی:
1 |
SELECT `EMPLOYEE_PAY_TBL`.`EMP_ID`, `EMPLOYEE_PAY_TBL`.`POSITION`, `EMPLOYEE_PAY_TBL`.`DATE_HIRE`, `EMPLOYEE_PAY_TBL`.`PAY_RATE`, `EMPLOYEE_PAY_TBL`.`DATE_LAST_RAISE`, `EMPLOYEE_PAY_TBL`.`SALARY`, `EMPLOYEE_PAY_TBL`.`BONUS` FROM `EMPLOYEE_PAY_TBL` |
در واقع بالا SELECT را با * یا کل فیلدها صدا زدیم، اما اگر بخواهیم فیلدهای خاصی بازگردند به صورت زیر عمل میکنیم:
1 2 |
q = EmployeePayTbl.objects.values_list('pay_rate') print(q) |
و اگر query را پرینت بگیریم دیگر سایر فیلدها وجود ندارند.
و خروجی دو خط کد بالا بدین صورت میشود:
1 |
<QuerySet [(None,), (Decimal('11.00'),), (None,), (None,), (Decimal('14.75'),), (Decimal('15.00'),)]> |
در واقع query بدین صورت شد:
1 |
SELECT `EMPLOYEE_PAY_TBL`.`PAY_RATE` FROM `EMPLOYEE_PAY_TBL` |
استفاده از WHERE:
تابع get فقط یک row برای شما برمیگرداند. به کد زیر دقت کنید:
1 2 |
q = EmployeePayTbl.objects.get(position="SHIPPER") q = print(q) |
کد بالا به دلیل اینکه داده SHIPPER بیشتر از یکبار در جدول وجود دارد خطای زیر را بر میگرداند:
1 |
get() returned more than one EmployeePayTbl -- it returned 2! |
کاربرد این تابع زمانی است که شما فقط یک row میخواهید برگردانید. مثال خوب این تابع در پی Primary Key ها میباشد.
به جای تابع get میتوان از تابع filter برای حل این موضوع استفاده کرد که به تفصیل جلوتر خواهیم پرداخت.
به query زیر دقت کنید:
1 |
select DATE_HIRE from EMPLOYEE_PAY_TBL where EMP_ID >= 311549902; |
نکته: فرض بر این است که شما بنا بر مطلب قبلی دادهها را import کردهاید.
خروجی SQL بالا چنین میشود:
1 2 3 4 5 6 7 8 |
+------------+ | DATE_HIRE | +------------+ | 1999-05-23 | | 2007-06-28 | | 2000-06-17 | | 2001-01-14 | +------------+ |
به تکه کد زیر دقت کنید:
1 2 |
q = EmployeePayTbl.objects.filter(emp_id__gte=311549902).values('date_hire') print(q) |
حتی وقتی که فیلد query را پرینت بگیریم دقیقا SQL بالا پرینت می شود:
1 |
SELECT `EMPLOYEE_PAY_TBL`.`DATE_HIRE` FROM `EMPLOYEE_PAY_TBL` WHERE `EMPLOYEE_PAY_TBL`.`EMP_ID` >= 311549902 |
اما پارامتر تابع filter کمی عجیب به نظر میرسد و بهتر است در آن تعمق شود:
متعیری که ساخته شده، از ترکیب اسم فیلد درون مدل و دو ـ به همراه ترکیب عمگرها ساخته شده، همین مثال بالا یعنی emp_id__gte از ترکیب emp_id به علاوه دو ـ و به همراه عملگر مورد نظر است. عملگر مورد نظر یعنی Less Than Equal ، در SQL میشود => که به معنای کوچکتر مساوی است. درون آن هم مساوی دیده میشود و هم مقدار اگر به کد SQL مورد نظر نگاه کنید، کاملا ترکیب پارامتر filter توصیف میشود.
فرمتی که تابع filter دارد به دو حالت است:
۱. یا متغیر به همراه دو ـ و به همراه یک عملگر
۲. یا متغیر تنها
تابع فیلتر از عملگرهای فرترنی که در شل اسکریپت هم استفاده میشوند استفاده میکند:
- gt به معنای Great Than
- lt به معنای Less Than
- e به معنای Equal
البته جلوتر ترکیبهای بیشتری به غیر از دو ترکیب بالا خواهیم دید.
نکته: برای مساوی نیاز نیست از یک ترکیب استفاده کنیم، فقط کافیست اسم فیلد نوشته شد.
یک سوالی که همیشه مطرح است ، چگونگی ساخت AND , OR و NOT میباشد. برای ساختن این سه عنصر جنگو تابع Q را معرفی کرده است. به کد زیر دقت کنید:
1 2 3 |
from django.db.models import Q q = EmployeePayTbl.objects.filter(~Q(emp_id__gte=311549902)).values('date_hire') print(q) |
تابع Q همانند filter شرط میپذیرد. با سه عملگر زیر میتوان NOT ، AND و OR را پیادهسازی کرد:
- ~ به معنی عملگر NOT
- | به معنی عملگر OR
- & به معنی عملگر AND
1 2 3 |
from django.db.models import Q q = EmployeePayTbl.objects.filter(~Q(emp_id__gte=311549902) & Q(position="SHIPPER") ).values('date_hire') print(q) |
در کد بالا هر چه emp_id که از عدد فوق بزرگتر نباشد را با هر row ی که position آن برابر SHIPPER باشد AND میکنیم، به طوری که خروجی SQL آن به صورت زیر میشود:
1 |
SELECT `EMPLOYEE_PAY_TBL`.`DATE_HIRE` FROM `EMPLOYEE_PAY_TBL` WHERE (NOT (`EMPLOYEE_PAY_TBL`.`EMP_ID` >= 311549902) AND `EMPLOYEE_PAY_TBL`.`POSITION` = SHIPPER) |
خروجی QuerySet آن نیز به صورت زیر میشود:
1 |
<QuerySet [{'date_hire': datetime.date(2006, 7, 22)}]> |
استفاده از LIKE:
برای استفاده از LIKE ، میتوان از ترکیبهای زیر استفاده نمود:
contains
- i
contains
startswith
- i
startswith
endswith
- i
endswith
- exact
- iexact
نکته: وقتی از i در اول هر کدام استفاده میشود به معنی case-insensitive میباشد.
به تکه کدهای زیر و SQL موجود در زیر آن دقت کنید:
1 |
q = EmployeePayTbl.objects.filter(position__contains="P" ).values('position') |
1 |
SELECT `EMPLOYEE_PAY_TBL`.`POSITION` FROM `EMPLOYEE_PAY_TBL` WHERE `EMPLOYEE_PAY_TBL`.`POSITION` LIKE BINARY %P% |
در کد بالا از %mystring% استفاده شد.
1 |
q = EmployeePayTbl.objects.filter(position__startswith="S" ).values('position') |
1 |
SELECT `EMPLOYEE_PAY_TBL`.`POSITION` FROM `EMPLOYEE_PAY_TBL` WHERE `EMPLOYEE_PAY_TBL`.`POSITION` LIKE BINARY S% |
در کد بالا هر رشتهای که با حرف s شروع میشود مد نظر است.
1 |
q = EmployeePayTbl.objects.filter(position__endswith="N" ).values('position') |
1 |
SELECT `EMPLOYEE_PAY_TBL`.`POSITION` FROM `EMPLOYEE_PAY_TBL` WHERE `EMPLOYEE_PAY_TBL`.`POSITION` LIKE BINARY %N |
در کد بالا هر رشتهای که با حرف N خاتمه مییابد مد نظر است.
1 |
q = EmployeePayTbl.objects.filter(position__exact="SHIPPER" ).values('position') |
1 |
SELECT `EMPLOYEE_PAY_TBL`.`POSITION` FROM `EMPLOYEE_PAY_TBL` WHERE `EMPLOYEE_PAY_TBL`.`POSITION` = SHIPPER |
در کد بالا عملگر تساوی مهم است.
نکته: برای NOT کردن هر کدام از Query های بالا میتوانید از تابع Q به صورتی که قبلتر گفته شد استفاده کنید.
مطالب مربوط به ORM جنگو ادامه خواهند داشت. منتظر باشید.