آموزش جنگو : جلسه سی و هشت | بررسی Lookup API در جنگو

در این جلسه به بررسی lookup api در جنگو خواهیم پرداخت . با ما همراه باشید . آموزش جنگو : جلسه سی و هشت | بررسی Lookup API در جنگوکار کردن با Lookup APIدر این بخش به بررسی API مربوط به Lookup پرداختیم . آشنایی با این متد ها و ویژگی ها قبل از ساخت lookup های سفارشی یا custom موردنیاز است .یک Lookup API دارای دو بخش است ; یک کلاس با نام RegisterLookupMixin که lookup در آن ثبت می شوند . به فرایند ثبت شدن lookup به اصطلاح register می گویند . بخش دوم Query Expression API است که شامل یک سری از متدها می باشد . این متد ها برای کلاس lookup باید نوشته شوند تا به عنوان یک lookup پذیرفته شوند .جنگو دو کلاس پایه (base class) دارد که از Query Expression API پیروی می کنند و تمام lookup های پیش فرض جنگو (و نه سفارشی) از آنها مشتق می شوند :بخش Lookup :برای انجام عملیات lookup روی یک فیلد این کلاس استفاده می شود . (مثل exact در field_name__exact)بخش Transform :برای انجام عملیات transform روی یک فیلد از این کلاس استفاده می شود .بیایید به بررسی Lookup بپردازیم . هر عبارت lookup (مثال field_name__exact) که می نویسید ,دارای سه بخش است .بخش فیلد ها که ممکن است بخاطر روابط حتی به چند فیلد هم برسید (برای مثال Book.objects.filter(author__best_friends__first_name...))بخش transform که ممکن است حذف شود . این بخش برای تبدیل داده به کار می رود . برای مثال می تواند داده را به Lowercase تبدیل کند . (برای مثال lower__first3chars__reversed__)بخش lookup که به صورت پیش فرض برابر با exact است . (مثال دیگر icontains__)کار کردن با Registration APIمفهوم RegisterLookupMixin :کلاسی از نوع mixin (بعدا توضیح می دهیم) است که Lookup API را روی مدل پیاده سازی می کند .جنگو از RegisterLookupMixin استفاده می کند تا به یک کلاس interface بدهد . این برای register کردن lookup روی خود کلاس و یا اشیا آن به کار می رود . دو مثال خوب شامل Field (کلاس پایه که برای ساخت فیلد های مدل به کار می رود) و Transform (کلاس پایه که برای تمام transformها در جنگو بکار می رود) می شوند .در ادامه متد های مربوط به این کلاس را بررسی می کنیم :1-متد register_lookup(lookup, lookup_name=None) :یک Lookup جدید را در کلاس یا اشیا آن ایجاد می کند . برای مثال :DateField.register_lookup(YearExact) User._meta.get_field(&quotdate_joined&quot).register_lookup(MonthExact)کد بالا دو lookup با نام YearExact و MonthExact را ایجاد می کند . YearExact را در DateField ایجاد می کند و MonthExact را در User.date_joined ایجاد می کند (register می کند) . این کد قرار است lookup را که از قبل وجود دارد ,بازنویسی کند (بنابراین هنوز کامل نیست) .به یاد داشته باشید که lookup های ایجاد شده در اشیا به lookup های ایجاد شده در کلاس ها اولویت دارند . در صورتی که آرگومان lookup_name را مقداردهی کنید ,از آن برای lookup استفاده خواهد شد . در غیر این صورت , lookup.lookup_name مورد استفاده خواهد بود .2-متد get_lookup(lookup_name) :آرگومان lookup_name را می گیرد و یک lookup را با همین lookup_name بازمیگرداند (lookup حتما باید در کلاس یا شی register شده باشد) . به صورت پیش فرض این متد ,تمام کلاس های والد را نیز (در صورت ارث بری) برای lookup موردنظر جستجو می کند تا آن را پیدا کند . در صورت پیدا کردن ,اولین مطابقت بازگردانده می شود .همچنین lookup هایی که روی اشیا ثبت شده باشند ,می توانند lookup های ثبت شده روی کلاس را بازنویسی کنند (lookup_name های آنها برای بازنویسی باید یکسان باشد) .3-متد get_lookups :یک دیکشنری از هر lookup_name که در کلاس یا اشیا آن ثبت شده باشد را بازمیگرداند . مقادیر value آنها برابر کلاس Lookup مربوط خواهند بود .4- متد get_transform(transform_name) :آرگومان transform_name را دریافت می کند و یک Transform که با آن مطابقت داشته باشد را بازمیگرداند . Transformباید در کلاس یا اشیا آن ثبت شده باشد . به صورت پیش فرض این متد ,تمام کلاس های والد را نیز (در صورت ارث بری) برای Transformموردنظر جستجو می کند تا آن را پیدا کند . در صورت پیدا کردن ,اولین مطابقت بازگردانده می شود .نکته : قابلیت ثبت کردن lookupبرای اشیا یک کلاس ,فقط در جنگو 4.1اضافه شده است .کار کردن با Query Expression APIدر این بخش قرار است تمام متد هایی را بررسی کنیم که به وسیله آنها جنگو می تواند Query ها را به کد SQLترجمه کند . از این متد ها در Transformها و یا aggregatesو غیره استفاده می شود . زمانی که یک کلاس از متد های زیر استفاده کند و آنها را پیاده سازی کند ,گفته می شود که این کلاس از query expression APIپیروی می کند .1-as_sql(compiler, connection) :قطعه کد SQLرا برای Queryایجاد می کند . یک تاپل به شکل (sql, params)بازمیگرداند که در آن sqlبرابر با رشته کد SQLتولید شده است و paramsبرابر یک لیست یا تاپل از پارامترهای Queryاست . علاوه بر اینها یک compilerنیز وجود دارد که شی ای از SQLCompilerاست . این شی دارای متد compileاست که می تواند برای کامپایل Queryهای دیگر به کار برود . Connectionنیز اتصال دیتابیسی است که برای اجرای Queryبه کار می رود . (قبلا با این مورد آشنا شده اید)فراخوانی expression.as_sqlکه در آن expressionهمان عبارت Queryماست ,معمولا اشتباه است . بجای این روش از compiler.compile(expression)استفاده کنید . compiler.compile ,فراخوانی متد های خاص از Queryرا پوشش می دهد .آرگومان های keyword argumentsنیز ممکن است در این متد جای بگیرند . البته در صورتی که برای مثال متد as_vendornameیا زیرکلاس ها نیاز به داده اضافی برای بازنویسی رشته SQLتولید شده داشته باشند .2-as_vendorname(compiler, connection) :مانند متد as_sqlاست . وقتی یک عبارت SQLتوسط compiler.compileکامپایل می شود ,جنگو ابتدا سعی می کند تا as_vendornameرا فراخوانی کند . در اینجا vendorname همان نام دیتابیسی است که از موتور دیتابیسی آن برای اجرای Queryاستفاده می شود . Vendornameیکی از مقادیر sqlite , oracle , postgresqlو یا mysqlرا می پذیرد .3- get_lookup(lookup_name) : Lookup ای را که با lookup_name داده شده مطابقت پیدا کند ,بازمیگرداند . برای مثال : self.output_field.get_lookup(lookup_name)4-get_transform(transform_name) : Lookup ای را که با transform_nameداده شده مطابقت پیدا کند ,بازمیگرداند . برای مثال : self.output_field.get_transform(transform_name)5-output_field :نوع کلاس بازگردانده شده توسط متد get_lookupرا تعریف می کند که باید یک شی از کلاس Field باشد .کار کردن با TransformTransformیک کلاس genericاست که برای پیاده سازی field transformationsبه کار می رود . یک مثال زیبا از Transformها , __year است که یک DateFieldرا به IntegerFieldتبدیل می کند .Transformها نیز مانند Lookupها استفاده می شوند . برای مثال date__yearهمانطور که قبلا گفتیم این کلاس از کلاس Query Expression APIپیروی می کند که به این معنی است که میتوانید Transformها را به یکدیگر زنجیر کنید . یعنی از چند Transformپشت سر هم استفاده کنید .1-Bilateral :یک ویژگی Booleanاست که نشان می دهد آیا این Transformباید برای rhsو lhsبه صورت همزمان اعمال شود یا خیر . نام دیگر این ویژگی تبدیل دو طرفه است . تبدیل های دو طرفه به همان ترتیبی که در Queryظاهر می شوند روی rhsها تنظیم می شوند . به طور پیش فرض این ویژگی روی Falseاست . (در مبحث نوشتن lookupهای سفارشی از این ویژگی استفاده می کنیم)2-Lhs : سمت چپ Transformرا نشان می دهد . آنچه که Transformروی آن تغییرات ایجاد می کند . از Query Expression APIپیروی می کند .3-lookup_name :نام Lookupاست که قبلا از آن استفاده کردیم . برای شناسایی Lookupبه کار می رود و نمی تواند دارای رشته _باشد .4-output_field : کلاسی که خروجی Transformرا ایجاد می کند را ,تعریف می کند . باید یک شی از Fieldباشد . به طور پیش فرض همان lhs.output_fieldاست .کار کردن با LookupLookupیک کلاس genericاست که برای پیاده سازی lookupها به کار می رود . lookupیک عبارت است که در Queryقرار می گیرد و یک lookup_nameدارد که برای مقایسه از نوع Trueیا Falseبین lhs(سمت چپ Query) و rhs(سمت راست Query) به کار می رود . شکل کلی آن به صورت <lhs>__<lookup_name>=<rhs>است .Lookupها همچنین می تواند مستقیما در QuerySetو متد filterقرار بگیرند . برای مثال :Book.objects.filter(LessThan(F("word_count"), 7500))یا حتی در متد annotateنیز استفاده شود .Book.objects.annotate(is_short_story=LessThan(F("word_count"), 7500))1-Lhs : سمت چپ Query ,آنچه lookupروی آن اجرا می شود . معمولا اشیایی که lookupروی آنها اجرا می شود ,از Query Expression API پیروی می کنند . همچنین ممکن است یک مقدار ساده باشند .2-Rhs : سمت راست Query ,آنچه lhsبا آن مقایسه می شود . این می تواند یک مقدار ساده باشد که به SQLکامپایل می شود . معمولا یک شی Fیا یک QuerySet.3-process_lhs(compiler, connection, lhs=None) : یک تاپل به شکل (lhs_string, lhs_params)بازمیگرداند که توسط compiler.compile(lhs)بازگردانده شده است . این متد می تواند برای تنظیم نحوه پردازش lhsبازنویسی شود .آرگومان compilerدر آن یک شی از SQLCompilerاست که مانند compiler.compile(lhs) برای کامپایل lhsبه کار می رود . آرگومان connectionنیز برای کامپایل SQLخاص کد به کار می رود . در انتها ,اگر lhsبرابر با Noneنباشد ,می توانید از آن (چون پردازش شده است) بجای self.lhsاستفاده کنید .4- process_rhs(compiler, connection) :مانند process_lhsاست اما برای rhsعمل می کند .در این جلسه به بررسی api مربوط به لوکاپ ها (lookups) در جنگو پرداختیم و چگونگی کارکرد آن را بررسی کردیم . در جلسه بعدی به نحوه کار کردن روابط دیتابیسی در جنگو خواهیم پرداخت و api مربوط به آنها را نیز بررسی خواهیم کرد .