ساخت یک Middleware سفارشی برای پروژه جنگو

سلام دوسِتان =))
در ابتدا بگم که من این پست رو به زبون انگلیسی هم در سایت مدیوم منتشر کردم اگر دلتون خواست میتونید از این لینک بخونید (اگر هم خواستید میتونید جفتشو بخونید، به خدا که من راضیم :دی )


ـ‌Middleware ها چی هستند؟

خیلی ساده بگم و گیجتون نکنم، Middleware ها در اصل کلاس‌هایی هستن که شامل یک یا چند تابع به خصوص هستند که قبل و بعد از تابع‌های View فراخوانی می‌شوند. برای اطلاعات بیش‌تر راجع به چرایی و چگونگی طی شدن این فرایند می‌تونید این بلاگ پست رو مطالعه کنید

ـ‌Middleware ها چه نیازمندی‌هایی دارند؟

تنها نیازمندی‌ای که یک کلاس داره تا به یک Middleware تبدیل بشه اینه که یکی از توابع زیر رو داشته باشه :

  • process_request
  • process_view
  • process_response
  • process_exception

البته که به دلیل تغییراتی که توی نسخه‌های جدید جنگو اعمال شده راه ساده برای نوشتن یک Middleware اینه که علاوه بر داشتن حداقل یکی از توابع فوق، کلاس ما از MiddlewareMixin نیز ارث‌بری کرده باشه. این کلاس توابع سازنده و ترتیب توابع فوق رو برامون آماده کرده و دیگه نیازی به اضافه کردن تابعی اضافه به کلاس خودمون نداریم.

ـ‌Middleware ها چگونه کار می‌کنند؟

هر پروژه جنگو در فایل settings.py یک لیست به نام MIDDLEWARES ( در نسخه های قدیمی‌تر MIDDLEWARES_CLASSES ) داره که حاوی آدرس تمام Middleware های سر راه ریکوئست/ریسپانس هست.
بعد از اینکه ریکوئست توسط فریمورک دریافت میشه WSGI Handler شروع به ساخت یک شئ HttpRequest میکنه و در این روند ریکوئست را به توابع process_request درون هر Middleware پاس میده. ( Middleware های درون لیست به ترتیب از بالا به پایین بررسی می‌شوند و اگر یک Middleware دارای process_request نبود هیچ اتفاقی نمی‌افته و WSGI Handler فقط از این کلاس چشم‌پوشی میکنه )
بعد از اینکه شئ مربوطه ساخته شد و از تمام Middleware ها گذشت نوبت به این میرسه که به تابع View تحویل داده بشه اما قبل از اون دوباره باید توابع process_view درون هر Middleware یه نگاهی بهش بندازن و در صورت تایید به view تحویل داده بشه =))

حواستون باشه که توابع process_request و process_view باید None را به عنوان خروجی بازگردانند. البته که می‌توانند یک شئ HttpRequest رو بازگرداند که در این صورت WSGI Handler به جای ادامه دادن روند فعلی خودش، به چرخه process_response میانبر میزنه و ریسپانس رو برمیگردونه =))

اگر یک تابع View با خطا برخورد کند WSGI Handler وارد چرخه process_exception میشه در غیر این صورت اگر یک شئ HttpResponse رو باز بگرداند وارد چرخه process_response خواهد شد.

بر خلاف process_request و process_view توابع process_response و process_exception فقط میتوانند محتوای ریسپانس را تغییر دهند.

خب دیگه بریم یکم کد بزنیم

در ابتدا یک پروژه جنگو با file tree زیر آماده می‌کنیم :

├── mysite
│   ├── manage.py
│   └── mysite   
│       ├── __init__.py 
│       ├── settings.py
│       ├── urls.py
│       └── wsgi.py
└── myapp   
    │   ├── __init__.py 
    │   ├── admin.py
    │   ├── apps.py
    │   ├── models.py
    │   ├── MyMiddleware.py
    │   ├── tests.py
    │   ├── urls.py
    └   └── views.py

حالا دوتا تابع view به پروژه خودمون اضافه میکنیم یکی برای تست process_request و یکی برای تست process_view :

https://gist.github.com/hamedsj/8b68e9b93d43904be1876395a77f8872

بعد از اون محتوای فایل mysite/urls.py به صورت زیر تغییر میدیم :

https://gist.github.com/hamedsj/ed7334e37fc69efc8d456545cc522d63

همچنین دوتا ویو ای که بالا ساختیم رو به myapp/urls.py مشابه زیر اضافه می‌کنیم :

https://gist.github.com/hamedsj/2388373a84d27e5581992c838257c740


حالا نوبت به نوشتن Middleware رسیده که محتوای اون رو داخل فایل MyMiddleware.py به شکل زیر قرار دادیم :

https://gist.github.com/hamedsj/83907cc5e4d2217b05ede97d6fe80a29

همانطور که مشاهده میکنید طبق محتوای فایل فوق، هر ریکوئست با متد GET اگر دارای پارامتر p باشه جواب “Hello World =)” رو تحویل میگیره و اگر ریکوئستی به تابع process_view_test ارسال شد و پارامتر p رو بین پارامترهای GET نداشت جواب “This method only work for this view =)” رو تحویل میگیره.

و در نهایت کافیه Middleware ای که ساختیم رو به لیست Middlewareها درون settings.py اضافه کنیم مانند زیر :

https://gist.github.com/hamedsj/6137ae10b256b9a627ea4c1c4a8f5089




نوبت به تست کدمون رسیده =))

Test 0 : curl http://127.0.0.1:8000/myview/
Output : Hello There =)

Test 1 : curl http://127.0.0.1:8000/myview/?p=2
Output : Hello World=)

Test 2 : curl http://127.0.0.1:8000/process_view_test/
Output : This method only work for this view =)

Test 3 : curl http://127.0.0.1:8000/process_view_test/?p=1
Output : Hello World=)


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

ممنونم از این که این پست رو مطالعه کردید
امیدوارم که براتون مفید باشه =))
لایک و کامنت فراموش نشه...
سوال یا نظری بود در خدمتم.
نوشته شده با ❤️ توسط کوچیکتون حمیدرضا شجراوی =)))