django channels sync async

تفاوت دو تکه کد زیر که از Django channels استفاده کرده است چیست؟

و

هر دو کد consumer هایی برای برقراری ارتباط websocket هستند. در اولی از ارتباط sync استفاده شده و در دومی از ارتباط async استفاده شده است.

در نتیجه:

در اولی:

اگر یک کانکشن برقرار شود، دیگر هیچ کانکشنی برقرار نمیشود تا کانکشن اولی بسته شود. چون کانکشن اول accept شده و هر کانکشن یک worker thread رو اشغال میکنه و تا زمانی که بسته نشه thread برای کانکشن بعدی باز نمیشه. این روش برای کارهای سریع مثل یه ارتباط با دیتابیس مناسب است اما برای یک ارتباط websocket که قرار است مدت زیادی باز بماند خوب نیست.

در دومی:

ارتباطات async است یعنی در واقع به آن گفته می شود که در قسمت await منتظر بمان تا I/O تکمیل شود اما در طول این انتظار ارتباطات دیگر می توانند برقرار شوند. در این حالت هر ارتباط به صورت یک task در event loop اجرا میشود. event loop ارتباطات دیگر را مدیریت میکند.

در واقع در حالت sync تسکها توسط worker ها انجام میشود و در حالت async تسک ها توسط event loop.

حالت sync مانند آشپزیست که هر قسمت غذا را کامل می پزد و بعد سراغ قسمت بعدی می رود اما حالت async چند ماهیتابه جلوی آشپز است که هر کدام را می چرخاند و سراغ بعدی می رود. این کار را event loop انجام می دهد که در پایتون در asyncio پیاده سازی شده است.

در دو consumer ای که نوشته شد هم داستان همین است. تا کانکشن اول بسته شود کانکشن بعدی باز نمی شود اما در حالت async این طور نیست و کانکشن اول در قسمت await وای میسه و event loop سراغ کانکشن های بعدی می رود.

کی از Message Queue استفاده میکنیم؟ وقتی که قرار باشد پیامی بین process ها یا consumer ها جابجا شوند. در واقع هر وقت توی django channels از channel layer بخایم استفاده کنیم باید از message q استفاده کنیم. در واقع channel layer همان message queue است.

Normalization vs Denormalization

کلاسهای زیر را در نظر بگیرید. این مدل طراحی مشکلات زیادی به وجوده میاره. با آپدیت شدن کلاس اول مجبور هستیم کلاس دوم و سوم رو هم آپدیت کنیم که با فراموش این نکته توی قسمت های مختلف کد باگهای زیادی ایجاد میشه. و همین آپدیت های اضافی کدهای اضافی در نتیجه باگهای بیشتر و سرعت کمتر رو به ارمغان میاره

depenancy زیادی بین کلاسها میبینید. در صورت آپدیت یک Service باید دو کلاس دیگر هم آپدیت شود و این موضوعی نیست که اتوماتیک انجام شود و ایراداتی در نرم افزار ایجاد میکند:

برای حل این موضوع باید کد را Normalize کنیم. یعنی تکرار به حداقل برسد و بجای تکرار اطلاعات موارد تکراری با کلید خارجی تبدیل شود:

حالا با آپدیت هر سرویس دو کلاس دیگر به صورت اتوماتیک آپدیت هستند.

گاهی Denormalization به درد میخورد. وقتی میخایم از یک جدول گزارشگیری داشته باشیم و نیاز به Join نباشد تکرار اطلاعات باعث افزایش بهره وری query می شود و …

پر کردن مودال با استفاده از اطلاعات فرم

نیاز بود که توی یک جدول اگر توی سلول یکی از ستونها کلیک کردیم یک مودال باز بشود. اما باید اطلاعاتی مربوط به آن ردیف به مودال پاس بدیم. متوجه شدم که این اطلاعات مربوط به ردیف مذکور را میتوان به عنوان یک پایامتر به سلول مربوطه اضافه کرد مثل:

توی خود مودال یک سری فیلد خالی تعریف میکنیم که بعدا با جاواساکریپ اطلاعات پارامترها رو به اون اضافه کنیم:

الان توی اسکریپت زیر از هر ردیف سلول مربوطه رو بر اساس اسم کلاس میگیریم. بعد از اون سلول پارامترم مربوطه که دیتا بهش وصل شده رو بر میداریم بعد همون مقدارها رو به مودال میدیم:

annotate و عدم اعمال Index

این 2 کد را در نظر بگیرید:

و

با تبدیل اولی به دومی زمان این query از 450 میلی ثانیه به 45 میلی ثانیه کاهش پیدا کرد. چرا؟

دلیل این بود که فیلدهای این مدل همگی Index بودند اما این ایندکسها اعمال نمی شدند چونکه annotate باعث میشود که کل جدول اسکن شود و عملا ایندکسها بی فایده باشند بنابراین حداقل st=0 را به قبل از annotate انتقال دادیم و این باعث شد برای annotate که اتفاقا از WHERE استفاده میکند از ایندکس استفاده شود.

مقایسه دو تکه کد

تفاوت دو کد زیر چیست و کدام بهتر است؟

و

در کد اول اگر thumbnail توسط کاربر انتخاب نشود یک فایل از مسیر mag آپلود میشود. و هنگام پاک شدن آبجکت مربوطه، اگر این آبجکت دارای این فایل پیشفرض بود پاک نشود که البته در این کد مربوطه خود به خود پاک می شود. پس یک باگ وجود دارد. گذشته از این باگ اگر 1000 بار کاربر بدون thumbnail فایل آپلود کند 1000 فایل تکراری ذخیره میشود.

در ضمن اگر فایل بهر دلیلی پاک شود یا نام آن تغییر کند سیستم دچار مشکل میشود.

در کد دوم اما اگر کاربر فایلی انتخاب نکند هیچ فایل پیش فرضی آپلود نمیشود بنابراین فایل تکراری دیده نمی شود و فضا هدر نمی روند.

از طرفی یک فایل static پاک نشده و هرکجا یک سند thumbnail نداشته باشد با متد get_thumbnail_url این فایل نشان داده میشود و دیگر سیستم دچار باگهای ناخواسته نمی شود.

تغییر queryset توی فرم جنگو

توی یک فرم میخوایم فیلدی که لیستی را به کاربر نشان میدهد را تغییری بدیم که همه مواردی که توی اون فیلد توی دیتابیس نیست را نشان ندهیم.

صحت سنجی فرمت فایل توی فرم جنگو

چطور توی یک فرم اگر یک فایل آپلود شده از یک فرمت خاص نبود ارور برگردونیم

مشکل ثبت مجدد فرم با رفرش

. توی کد زیر بعد از ثبت کردن فرم اگر صفحه را رفرش کنیم همان فرم دوباره ثبت میشود.

مشکل در فروم جنگو این جوری توضیح داده شده است:

یعنی بعد از POST موفق باید فرم را redirect کنیم که با این کار صفحه جدید با GET فراخوانی میشود در نتیجه اگر رفرش کنیم باز هم در خواست GET ارسال میگردد. یعنی کد را به شکل زیر تغییر میدهیم.

serializer توی Django Rest Framework با دیتای ورودی چیکار میکنه؟

بهترین روش یادگیری یه فریم ورک خوندن کد خود فریم ورک و داکیومنت توی خود کد هست. برای serializer توی جنگو یک کامنت هست توی rest_framework/serializer.py که:

خیلی خوب توضیح میده که اگر به serializer پارامتر data رو پاس داده باشیم تابع is_valid قابل استفاده است. و initial_data هم در دسترس هست که همون دیتایی هست که به API پاس داده شده. بعد از is_valid این داده ورودی به valid شده تبدیل میشه که میتونیم توی validated_data ببینیم. مثلا اگر Id به object مربوطه تبدیل میشه. و errors و data هم در دسترس خواهد بود. data درواقع اون رکورد جدیدی هست که ایجاد شده است.

مثال زیر رو ببینید:

میبینید که بعد serializer.is_valid() مقادیر مربوطه رو پرینت کردم.

مثال خروجی هم در ادامه میبینید:

بازنویسی serializer توی Django Rest Framework

توی serializer های DRF گاهی لازمه وقتی متد list() اون صدا زده میشه باید قبلش دیتایی که ازش گرفته میشه تغییری بدیم برای این کار از متد to_representaion استفاده میکنیم.