اصلی ترین وظیفه هر برنامه backend از جمله برنامه هایی که در django می نویسیم پردازش request های ارسالی کاربر و سپس برگرداندن یک response مناسب می باشد. در واقع entry point هر برنامه django درخواستی است که از سمت کاربر ارسال شده. بنابراین دسترسی داشتن به request جاری در قسمت های مختلف برنامه برای برنامه نویس اهمیت بالایی دارد.
همانطور که دیده اید در django ما به request جاری در بعضی قسمت ها مانند views یا متد __call__ در middleware ها دسترسی داریم چون در ورودی توابع آن را دریافت می کنیم اما اگر بخواهیم در قسمت های دیگر از جمله model ها، form ها، template tag ها و... به request جاری دسترسی داشته باشیم باید چه کار کنیم؟
در ادامه به پاسخ این مسئله خواهیم پرداخت. یک راه این است که لایه به لایه request را از view پاس بدهیم تا به مکان مورد نظر ما برسد. البته این یک راه حل عمومی نخواهد بود و ممکن است در مواقعی ممکن نباشد.
یک راه حل دیگر اما استفاده از middleware برای رسیدن به این منظور است، که شرح آن در پی خواهد آمد. ابتدا یک middleware به صورت زیر درست می کنیم:
from threading import current_thread _requests = {} def get_request(): return _requests[current_thread()] class GlobalRequestMiddleware(object): def __init__(self, get_response): self.get_response = get_response def __call__(self, request): _requests[current_thread()] = request return self.get_response(request)
در ابتدا نیاز داریم که request مان در thread فعلی را دریافت کنیم و برای همین هم به تابع current_thread
را import کردیم. دلیل این کار این هست که وب سرور های جنگو ممکن است به صورت multithread باشند. thread های متعلق به یک process روی یک حافظه مشترک اجرا می شوند، فلذا باید مطمئن شویم request متعلق به thread فعلی را برمیگردانیم نه request دریافت شده توسط thread های دیگر را.(دستور runserver به طور پیشفرض multithread است و در gunicorn هم می توان این کار را کرد)
سپس middleware مربوطه را در settings.py ثبت می کنیم(فرض کنید middleware در app بلاگ ساخته شده) :
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', // our new middleware 'blog.middlewares.GlobalRequestMiddleware' ]
و حالا می توانیم request جاری را در بقیه بخش ها بدون این که نیاز به پاس دادن های اضافی request داشته باشیم، بگیریم. برای مثال فرض کنید می خواهیم یک property در مدل post داشته باشیم که آیا که آیا کاربر لاگین کرده ما، پست را ذخیره کرده یا نه. برای این کار در models.py و مدل post می نویسیم:
from blog.middlewares import get_request class Post(models.Model): // ... @property def is_bookmarked(self): user = get_request().user if user.is_anonymous: return False return User.objects.filter(bookmarks=self).filter(id=user.id).exists()
موفق باشید.