مقدمه‌ای بر نمایش‌های مبتنی بر کلاس در جنگو: مزایا، ساختار و نحوه استفاده

این مقاله نمایش‌های مبتنی بر کلاس (Class-Based Views) در جنگو را معرفی می‌کند، تفاوت آن‌ها با نمایش‌های تابعی را توضیح می‌دهد، تاریخچه و تکامل generic views را بررسی می‌کند، و نحوه استفاده، پیکربندی، ارث‌بری و override کردن متدها را با مثال‌های کاربردی شرح می‌دهد.

نمایش مبتنی بر کلاسCBV، generic viewsmixins

~6 دقیقه مطالعه • بروزرسانی ۲۳ اسفند ۱۴۰۴

مقدمه

نمایش‌های مبتنی بر کلاس یا Class-Based Views (CBVs) در جنگو روشی جایگزین برای پیاده‌سازی viewها هستند. به جای نوشتن یک تابع، شما یک کلاس می‌سازید که منطق view را در متدهای مختلف سازمان‌دهی می‌کند. این روش جایگزین نمایش‌های تابعی نیست، اما مزایای مهمی دارد.


مزایای نمایش‌های مبتنی بر کلاس

  • سازمان‌دهی بهتر منطق مربوط به متدهای HTTP مانند GET و POST.
  • استفاده از تکنیک‌های شیءگرایی مانند ارث‌بری و mixins.
  • قابلیت توسعه‌پذیری و انعطاف‌پذیری بیشتر نسبت به نمایش‌های تابعی.

تاریخچه و تکامل generic views

در ابتدا تنها نمایش‌های تابعی وجود داشتند: جنگو یک HttpRequest به تابع شما می‌داد و انتظار داشت یک HttpResponse برگردانید. بعدها، الگوهای تکراری در viewها شناسایی شد و generic views تابعی معرفی شدند. اما این نوع generic views محدود بودند و امکان سفارشی‌سازی عمیق نداشتند.


برای رفع این محدودیت‌ها، generic views مبتنی بر کلاس معرفی شدند. این نسخه جدید با استفاده از mixinها و ارث‌بری، انعطاف‌پذیری بسیار بیشتری ارائه می‌دهد و برای پروژه‌های واقعی مناسب‌تر است.


چگونه از نمایش‌های مبتنی بر کلاس استفاده کنیم؟

در نمایش‌های تابعی، منطق مربوط به متدهای HTTP معمولاً با شرط‌ها مدیریت می‌شود:


def my_view(request):
    if request.method == "GET":
        return HttpResponse("result")

اما در CBVها، هر متد HTTP در یک متد جداگانه قرار می‌گیرد:


from django.views import View
from django.http import HttpResponse

class MyView(View):
    def get(self, request):
        return HttpResponse("result")

نحوه اتصال CBV به URL

از آنجا که URL resolver جنگو انتظار یک تابع قابل فراخوانی دارد، CBVها متد as_view() را ارائه می‌دهند:


from django.urls import path
from myapp.views import MyView

urlpatterns = [
    path("about/", MyView.as_view()),
]

این متد یک instance از کلاس می‌سازد، setup() را اجرا می‌کند و سپس dispatch() را فراخوانی می‌کند تا متد مناسب HTTP را اجرا کند.


پیکربندی CBV با ارث‌بری

ساده‌ترین روش سفارشی‌سازی، ارث‌بری و override کردن ویژگی‌ها یا متدهاست:


class GreetingView(View):
    greeting = "Good Day"

    def get(self, request):
        return HttpResponse(self.greeting)

class MorningGreetingView(GreetingView):
    greeting = "Morning to ya"

پیکربندی CBV با as_view()

می‌توانید ویژگی‌های کلاس را هنگام فراخوانی as_view() نیز تنظیم کنید:


urlpatterns = [
    path("about/", GreetingView.as_view(greeting="G'day")),
]

نکته مهم: ویژگی‌هایی که از طریق as_view() تنظیم می‌شوند، تنها یک بار هنگام بارگذاری URLها مقداردهی می‌شوند، نه در هر درخواست.


جمع‌بندی

نمایش‌های مبتنی بر کلاس در جنگو یک ابزار قدرتمند برای سازمان‌دهی بهتر کد، استفاده مجدد از منطق، و توسعه‌پذیری بیشتر هستند. با استفاده از ارث‌بری، mixinها و متدهای HTTP جداگانه، می‌توان viewهایی ساخت که هم خواناتر باشند و هم قابلیت نگهداری بیشتری داشته باشند.

مقدمه

میکسین‌ها یکی از مهم‌ترین ابزارهای شیءگرایی در جنگو هستند که امکان ترکیب رفتارهای مختلف را از طریق چندوراثتی فراهم می‌کنند. در نمایش‌های مبتنی بر کلاس (CBV)، میکسین‌ها نقش کلیدی در ایجاد قابلیت‌های قابل‌استفاده مجدد دارند. این مقاله به بررسی نحوه استفاده از میکسین‌ها، مدیریت فرم‌ها و اعمال دکوریتورها در CBVها می‌پردازد.


میکسین‌ها در نمایش‌های مبتنی بر کلاس

میکسین‌ها کلاس‌هایی هستند که رفتار یا ویژگی خاصی را ارائه می‌دهند و قرار نیست به‌تنهایی استفاده شوند. آن‌ها معمولاً همراه با یک کلاس اصلی مانند View ترکیب می‌شوند.


برای مثال، در generic views جنگو، میکسینی به نام TemplateResponseMixin وجود دارد که متد render_to_response() را تعریف می‌کند. وقتی این میکسین با کلاس پایه View ترکیب می‌شود، نتیجه یک TemplateView است که:

  • درخواست‌ها را به متدهای مناسب هدایت می‌کند (رفتار کلاس View)
  • قالب را با استفاده از template_name رندر می‌کند (رفتار TemplateResponseMixin)

محدودیت‌های استفاده از میکسین‌ها

اگرچه میکسین‌ها بسیار مفید هستند، اما استفاده بیش از حد از آن‌ها می‌تواند باعث پیچیدگی شود. هرچه رفتارها در میکسین‌های بیشتری پخش شوند، خواندن کلاس نهایی و تشخیص اینکه هر متد از کجا آمده دشوارتر می‌شود.


نکته مهم: در CBVها فقط یک کلاس والد می‌تواند از View ارث ببرد؛ بقیه باید میکسین باشند. مثلاً ترکیب مستقیم ProcessFormView و ListView امکان‌پذیر نیست، چون هر دو از View ارث می‌برند.


مدیریت فرم‌ها با نمایش‌های مبتنی بر کلاس

یک نمایش تابعی ساده برای مدیریت فرم ممکن است این‌گونه باشد:


def myview(request):
    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect("/success/")
    else:
        form = MyForm(initial={"key": "value"})

    return render(request, "form_template.html", {"form": form})

نسخه مبتنی بر کلاس همان منطق را تمیزتر و قابل‌گسترش‌تر ارائه می‌دهد:


class MyFormView(View):
    form_class = MyForm
    initial = {"key": "value"}
    template_name = "form_template.html"

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {"form": form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            return HttpResponseRedirect("/success/")
        return render(request, self.template_name, {"form": form})

این ساختار امکان سفارشی‌سازی آسان را فراهم می‌کند:

  • تغییر form_class یا template_name
  • override کردن متدهای get() یا post()
  • ارسال مقادیر جدید از طریق as_view()

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

از آنجا که CBVها تابع نیستند، اعمال دکوریتورها روی آن‌ها کمی متفاوت است. دو روش اصلی وجود دارد:


۱. دکوریتور در URLconf

می‌توان خروجی as_view() را دکوریت کرد:


urlpatterns = [
    path("about/", login_required(TemplateView.as_view(template_name="secret.html"))),
    path("vote/", permission_required("polls.can_vote")(VoteView.as_view())),
]

۲. دکوریتور روی خود کلاس

برای اینکه همه instanceهای یک CBV دکوریت شوند، باید dispatch() را دکوریت کرد:


class ProtectedView(TemplateView):
    template_name = "secret.html"

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

یا نسخه کوتاه‌تر:


@method_decorator(login_required, name="dispatch")
class ProtectedView(TemplateView):
    template_name = "secret.html"

اعمال چند دکوریتور


decorators = [never_cache, login_required]

@method_decorator(decorators, name="dispatch")
class ProtectedView(TemplateView):
    template_name = "secret.html"

دکوریتورها به ترتیب اجرا می‌شوند.


جمع‌بندی

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

نوشته و پژوهش شده توسط دکتر شاهین صیامی