فصل ۱۴: Messages Framework — نمایش پیامها به کاربر

۱. مقدمه — چرا باید پیامها را جدی بگیریم؟
تقریباً توی هر سایت یا اپلیکیشن، یک بخش خیلی مهم تعامل با کاربر، اعلام نتیجه عملیات هست.
کاربر نمیتونه ذهن توسعهدهنده رو بخونه 😅؛ پس باید بفهمه که:
- محصولش ثبت شد؟
- خطایی توی فرم ثبتنام بود؟
- خریدش موفق بود یا ناموفق؟
- عملیات حذف رو تایید کرد یا لغو؟
همه اینها یعنی باید به کاربر Feedback بدهیم.
سناریوی فروشگاه آنلاین:
تو فروشگاه آنلاین ما، کاربر گاهی:
- محصول اضافه میکنه
- محصول حذف میکنه
- خرید انجام میده
- آدرس پستیش رو تغییر میده
در همه این مراحل ما باید بهش پیامی متنی بدیم:
- سبز → موفقیت: «محصول با موفقیت اضافه شد.»
- قرمز → خطا: «خطا در حذف محصول.»
- زرد → هشدار: «آیا مطمئن هستید که میخواهید محصول را حذف کنید؟»
- آبی → اطلاعرسانی: «سایت شنبهها بین 1 تا 3 بامداد بروزرسانی میشود.»
۲. Messages Framework در Django چیست؟
Django یک سیستم داخلی به اسم Messages Framework داره که کمک میکنه پیامها رو به صورت موقت نگه داریم و تو صفحه بعدی نمایش بدیم.
📌 نکته مهم:
- پیامها فقط برای یک درخواست بعدی نگه داشته میشوند (مثلاً بعد از انجام عملیات و انتقال به صفحه دیگر).
- بر اساس Session یا Cookies پیادهسازی شده.
- نیازی به نوشتن کد دیتابیس برای ذخیره پیامهای موقت نداریم.
۳. بررسی فعال بودن Messages Framework
این سیستم به صورت پیشفرض فعال است، ولی باید مطمئن باشیم:
۳.۱. INSTALLED_APPS
INSTALLED_APPS = [
# ...
'django.contrib.messages',
]
۳.۲. MIDDLEWARE
MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware', # لازم برای Session-based Messages
'django.contrib.messages.middleware.MessageMiddleware', # مدیریت پیامها
]
۳.3. Context Processor
در بخش TEMPLATES → context_processors:
'context_processors': [
# ...
'django.contrib.messages.context_processors.messages',
]
📌 این باعث میشه داخل قالبها (templates) همیشه متغیر messages در دسترس باشه.
۴. انواع پیامها در Django
Django دستهبندی مشخصی برای پیامها داره:
| روش استفاده در View | سطح پیام (Level) | رنگ پیشنهادی در UI |
|---|---|---|
messages.debug | DEBUG | خاکستری (برای توسعه) |
messages.info | INFO | آبی (اطلاعرسانی) |
messages.success | SUCCESS | سبز (موفقیت) |
messages.warning | WARNING | زرد (هشدار) |
messages.error | ERROR | قرمز (خطا) |
۵. اولین مثال — پیام بعد از ثبت محصول
فرض کن فرم افزودن محصول داریم که بعد از ذخیره شدن موفقیتآمیز، پیام موفقیت به کاربر نشون بده.
۵.۱. views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import ProductForm
def add_product(request):
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES) # دادهها و فایلها
if form.is_valid():
form.save()
# پیام موفقیت
messages.success(request, "✅ محصول با موفقیت اضافه شد.")
return redirect('product_list')
else:
# پیام خطا
messages.error(request, "❌ خطا در ثبت محصول. لطفاً موارد گفته شده را بررسی کنید.")
else:
form = ProductForm()
return render(request, 'add_product.html', {'form': form})
۶. نمایش پیامها در قالب HTML
برای نمایش پیامها باید تو قالبمون حلقه for بزنیم روی متغیر messages.
📌 معمولاً این کد رو توی base.html قرار میدیم تا همه صفحات پیامها رو نمایش بدن.
۶.۱. base.html
{% if messages %}
<div class="container mt-3">
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
</div>
{% endif %}
۶.۲. توضیح:
message.tags→ اتوماتیک بهsuccess،error،warningو غیره تغییر میکنه و برای Bootstrap عالیه.- دکمه
btn-closeدر Bootstrap کاربر رو قادر میکنه پیام رو ببنده. - کلاس
fade showانیمیشن محو شدن پیام رو اضافه میکنه.
۷. ترکیب پیامها با عمل حذف محصول
وقتی محصولی رو حذف میکنیم، کاربر باید متوجه بشه:
from django.shortcuts import get_object_or_404
from django.contrib import messages
from .models import Product
def delete_product(request, pk):
product = get_object_or_404(Product, pk=pk)
product.delete()
messages.success(request, f"🗑 محصول «{product.name}» با موفقیت حذف شد.")
return redirect('product_list')
۸. نکته مهم: Redirect بعد از POST (الگوی PRG)
در Django وقتی از فرمها استفاده میکنیم و پیام ارسال میکنیم، باید از الگوی Post/Redirect/Get استفاده کنیم:
- کاربر فرم رو ارسال میکنه (POST)
- عملیات انجام میشه و پیام اضافه میشه
redirect()کاربر رو به صفحه لیست یا جزئیات میفرسته- پیام نمایش داده میشه
📌 این باعث میشه با F5 (رفرش)، عمل دوباره انجام نشه.
۹. سطحبندی پیشرفته پیامها
هر پیام یک سطح (Level) عددی داره که Django بر اساسش تصمیم میگیره:
- DEBUG → 10
- INFO → 20
- SUCCESS → 25
- WARNING → 30
- ERROR → 40
میتونی بگی مثلاً پیامهای از سطح WARNING به پایین اصلاً ذخیره نشه:
from django.contrib import messages
messages.set_level(request, messages.WARNING) # فقط Warning و Error و...
۱۰. استفاده از Tags سفارشی
فرض کن توی Bootstrap کلاسهای خاص خودتو داری. میتونی پیامها رو Map کنی:
from django.contrib.messages import constants as message_constants
MESSAGE_TAGS = {
message_constants.DEBUG: 'secondary',
message_constants.INFO: 'info',
message_constants.SUCCESS: 'success',
message_constants.WARNING: 'warning',
message_constants.ERROR: 'danger',
}
📌 اینو تو settings.py بذار تا هر پیام سطح مشخصی بگیره.
۱۱. ترکیب پیام با شرایط خاص (مثال خرید)
def checkout(request):
cart = request.session.get('cart', {})
if not cart:
messages.warning(request, "سبد خرید شما خالی است.")
return redirect('cart_view')
if process_payment(cart):
messages.success(request, "پرداخت با موفقیت انجام شد. سفارش شما ثبت گردید.")
request.session['cart'] = {}
else:
messages.error(request, "مشکلی در پرداخت پیش آمد.")
return redirect('order_history')
۱۲. چند پیام در یک درخواست
مشکلی نداره چند پیام پشت سر هم اضافه بشه:
messages.info(request, "سایت فردا صبح بهروزرسانی میشود.")
messages.success(request, "محصول ثبت شد.")
messages.warning(request, "موجودی انبار رو بررسی کنید.")
توی قالب همه رو میبینی.
۱۳. پیامها با طول عمر Session
پیشفرض، پیامها یکبار نمایش داده میشن، ولی میتونی از storage backendهای دیگر استفاده کنی، مثلاً Session Storage یا Cookie Storage.
در settings.py:
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
۱۴. خطاهای رایج
| مشکل | دلیل | راهحل |
|---|---|---|
| پیام نمایش داده نمیشود | حلقه نمایش در قالب وجود ندارد | {% for message in messages %} اضافه کن |
| پیام بدون استایل | Bootstrap یا CSS وصل نشده | لینک CSS رو درست اضافه کن |
| پیام بعد از رفرش نیست | رفتار طبیعی Framework | اگر موندگاری بخوای، باید Custom Storage بسازی |
۱۵. نکات بهترین عملکرد (Best Practices)
- همیشه بعد از عملیات POST ریدایرکت کن → هم از ارسال دوباره جلوگیری میکنه، هم پیام درست نشون داده میشه.
- پیامها در base.html باشن، که توی همه صفحات دیده بشه.
- سطوح پیام رو درست استفاده کن (از error برای همه چیز استفاده نکن!)
- ترکیب با AJAX → اگه فرمها رو با AJAX ارسال میکنی، پیامها رو تو JSON پاسخ بده.
- اموجی یا آیکن اضافه کن → کاربر سریعتر منظور رو میفهمه.
۱۶. مثال کامل CRUD با پیامها در فروشگاه آنلاین
views.py
# لیست محصولات
class ProductListView(ListView):
model = Product
template_name = 'product_list.html'
context_object_name = 'products'
paginate_by = 6
# جزئیات
class ProductDetailView(DetailView):
model = Product
template_name = 'product_detail.html'
# افزودن محصول
class ProductCreateView(CreateView):
model = Product
fields = ['name', 'price', 'description', 'image']
template_name = 'product_form.html'
success_url = reverse_lazy('product_list')
def form_valid(self, form):
messages.success(self.request, "محصول با موفقیت اضافه شد.")
return super().form_valid(form)
# ویرایش
class ProductUpdateView(UpdateView):
model = Product
fields = ['name', 'price', 'description', 'image']
template_name = 'product_form.html'
success_url = reverse_lazy('product_list')
def form_valid(self, form):
messages.info(self.request, "محصول با موفقیت ویرایش شد.")
return super().form_valid(form)
# حذف
class ProductDeleteView(DeleteView):
model = Product
template_name = 'product_confirm_delete.html'
success_url = reverse_lazy('product_list')
def delete(self, request, *args, **kwargs):
messages.warning(request, "محصول حذف شد.")
return super().delete(request, *args, **kwargs)
۱۷. نتیجهگیری
الان تو سناریوی فروشگاه آنلاین ما:
- هر عملیاتی (افزودن، حذف، خرید) نتیجهش به کاربر نمایش داده میشه.
- پیامها استایل Bootstrap دارن.
- از تکرار درخواست جلوگیری میشه.
- کاربر همیشه میدونه چی اتفاق افتاده.