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 استفاده میکنیم.

یک باگ ساده و یک راه حل ساده تر

کد زیر یک باگ جالب داره.

در صورتی که branch انتخاب نشده باشه cleaned_data.get(“branch”).name این اکسپشن میده. برای اصلاحش باید یه تغییر ساده بدیم