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

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

نمایش عمومی جنگو، ListViewDetailViewcontext_object_name، get_context_data

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

مقدمه

توسعه وب معمولاً شامل تکرار الگوهای مشابه است: نمایش لیست اشیا، نمایش جزئیات یک شیء، مدیریت فرم‌ها و غیره. جنگو برای کاهش این تکرار، نمایش‌های عمومی مبتنی بر کلاس (Generic CBVs) را ارائه می‌دهد تا توسعه‌دهندگان بتوانند بدون نوشتن کد اضافی، سریع‌تر به نتایج برسند.


چرا نمایش‌های عمومی ایجاد شدند؟

نمایش‌های عمومی برای ساده‌سازی کارهای پرتکرار طراحی شده‌اند. این نمایش‌ها الگوهای رایج را شناسایی کرده و آن‌ها را در قالب کلاس‌هایی قابل استفاده مجدد ارائه می‌کنند. برای مثال:

  • نمایش لیست اشیا
  • نمایش جزئیات یک شیء
  • نمایش آرشیوهای سال/ماه/روز
  • ایجاد، ویرایش و حذف اشیا

گسترش نمایش‌های عمومی

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

  • زیرکلاس‌سازی کرد
  • ویژگی‌ها را override کرد
  • متدها را بازنویسی کرد

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


نمایش‌های عمومی برای اشیا

جنگو برای نمایش داده‌های پایگاه داده، generic views قدرتمندی مانند ListView و DetailView ارائه می‌دهد.


مدل‌های نمونه


class Publisher(models.Model):
    name = models.CharField(max_length=30)
    ...

class Author(models.Model):
    name = models.CharField(max_length=200)
    ...

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField("Author")
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    publication_date = models.DateField()

ایجاد یک ListView


class PublisherListView(ListView):
    model = Publisher

اتصال به URL


urlpatterns = [
    path("publishers/", PublisherListView.as_view()),
]

نام‌گذاری خودکار قالب

اگر template_name را مشخص نکنید، جنگو مسیر قالب را به صورت خودکار تعیین می‌کند:

  • نام اپ: books
  • نام مدل: Publisher → publisher
  • نوع نمایش: list

مسیر نهایی:


books/publisher_list.html

نمونه قالب


{% extends "base.html" %}

{% block content %}

Publishers

    {% for publisher in object_list %}
  • {{ publisher.name }}
  • {% endfor %}
{% endblock %}

ایجاد context دوستانه‌تر

به‌طور پیش‌فرض، ListView دو متغیر به قالب ارسال می‌کند:

  • object_list
  • publisher_list (نام مدل به صورت lowercase)

برای تغییر نام متغیر:


class PublisherListView(ListView):
    model = Publisher
    context_object_name = "my_favorite_publishers"

افزودن context اضافی

برای ارسال داده‌های بیشتر به قالب، get_context_data() را override کنید:


class PublisherDetailView(DetailView):
    model = Publisher

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["book_list"] = Book.objects.all()
        return context

همیشه super() را فراخوانی کنید تا context والد حفظ شود.


جمع‌بندی

نمایش‌های عمومی مبتنی بر کلاس در جنگو ابزاری قدرتمند برای کاهش کدهای تکراری و ساخت سریع صفحات لیست و جزئیات هستند. با استفاده از ListView، DetailView و قابلیت‌هایی مانند context_object_name و get_context_data می‌توان نمایش‌هایی تمیز، قابل نگهداری و قابل گسترش ایجاد کرد.

مقدمه

Generic Views در جنگو به‌طور پیش‌فرض با مدل‌ها کار می‌کنند، اما همیشه لازم نیست تمام اشیا را نمایش دهیم. گاهی باید زیرمجموعه‌ای از داده‌ها را نشان دهیم، داده‌ها را فیلتر کنیم، یا قبل و بعد از واکشی شیء کارهای اضافی انجام دهیم. این مقاله دقیقاً همین موارد را بررسی می‌کند.


استفاده از queryset برای کنترل داده‌ها

در تمام Generic Viewsهایی که روی یک شیء یا مجموعه‌ای از اشیا کار می‌کنند، می‌توانیم به‌جای استفاده از model، مستقیماً queryset را مشخص کنیم:


class PublisherDetailView(DetailView):
    context_object_name = "publisher"
    queryset = Publisher.objects.all()

استفاده از model = Publisher در واقع میان‌بری برای همین queryset است. اما با استفاده از queryset می‌توانیم داده‌ها را فیلتر کنیم.


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


class BookListView(ListView):
    queryset = Book.objects.order_by("-publication_date")
    context_object_name = "book_list"

مثال: نمایش کتاب‌های یک ناشر خاص


class AcmeBookListView(ListView):
    context_object_name = "book_list"
    queryset = Book.objects.filter(publisher__name="ACME Publishing")
    template_name = "books/acme_list.html"

در اینجا از یک قالب سفارشی نیز استفاده شده است تا با لیست اصلی کتاب‌ها تداخل نداشته باشد.


فیلتر پویا با استفاده از get_queryset

گاهی لازم است داده‌ها را بر اساس مقداری که از URL دریافت می‌کنیم فیلتر کنیم. برای این کار get_queryset() را override می‌کنیم.

URL نمونه


path("books/<publisher>/", PublisherBookListView.as_view()),

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


class PublisherBookListView(ListView):
    template_name = "books/books_by_publisher.html"

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.kwargs["publisher"])
        return Book.objects.filter(publisher=self.publisher)

در اینجا self.kwargs شامل پارامترهای URL است. همچنین می‌توانیم از self.request.user برای فیلتر کردن بر اساس کاربر فعلی استفاده کنیم.


افزودن ناشر به context


def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context["publisher"] = self.publisher
    return context

انجام کارهای اضافی قبل یا بعد از واکشی شیء

گاهی لازم است قبل یا بعد از واکشی شیء، عملیات اضافی انجام دهیم. مثلاً فرض کنید می‌خواهیم آخرین زمان مشاهده یک نویسنده را ذخیره کنیم.

مدل نمونه


class Author(models.Model):
    name = models.CharField(max_length=200)
    last_accessed = models.DateTimeField()

URL مربوط به جزئیات نویسنده


path("authors/<int:pk>/", AuthorDetailView.as_view(), name="author-detail"),

Override کردن get_object


class AuthorDetailView(DetailView):
    queryset = Author.objects.all()

    def get_object(self):
        obj = super().get_object()
        obj.last_accessed = timezone.now()
        obj.save()
        return obj

نکته: DetailView به‌طور پیش‌فرض از پارامتر pk برای یافتن شیء استفاده می‌کند. اگر نام پارامتر URL متفاوت باشد، می‌توان pk_url_kwarg را تغییر داد.


جمع‌بندی

با استفاده از queryset سفارشی، override کردن get_queryset()، افزودن context اضافی و override کردن get_object() می‌توان کنترل کامل روی داده‌های نمایش داده‌شده در Generic Views داشت. این تکنیک‌ها به شما اجازه می‌دهند نمایش‌هایی پویا، قابل‌گسترش و حرفه‌ای بسازید.

Introduction

Django’s generic class‑based views (CBVs) provide powerful tools for displaying objects from the database. However, you often need to show only a subset of objects, filter them dynamically, or perform additional work when retrieving an object. This article explores these techniques in detail.


Using a Custom QuerySet

Most generic views accept a model attribute, but you can also specify the objects directly using queryset. This gives you full control over which objects are visible in the view.


class PublisherDetailView(DetailView):
    context_object_name = "publisher"
    queryset = Publisher.objects.all()

Using model = Publisher is simply shorthand for the queryset above. By defining a filtered queryset, you can restrict what the view displays.


Example: Ordering Books by Publication Date


class BookListView(ListView):
    queryset = Book.objects.order_by("-publication_date")
    context_object_name = "book_list"

Example: Books from a Specific Publisher


class AcmeBookListView(ListView):
    context_object_name = "book_list"
    queryset = Book.objects.filter(publisher__name="ACME Publishing")
    template_name = "books/acme_list.html"

Here we also specify a custom template to avoid reusing the default list template.


Dynamic Filtering with get_queryset()

Hardcoding values in the queryset is rarely ideal. Instead, you can filter objects dynamically based on URL parameters by overriding get_queryset().

URL Pattern with a Dynamic Segment


path("books/<publisher>/", PublisherBookListView.as_view()),

View That Filters Books by Publisher Name


class PublisherBookListView(ListView):
    template_name = "books/books_by_publisher.html"

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name=self.kwargs["publisher"])
        return Book.objects.filter(publisher=self.publisher)

The self.kwargs dictionary contains values captured from the URL. You can also use self.request.user or any other logic to filter objects.


Adding the Publisher to the Template Context


def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context["publisher"] = self.publisher
    return context

Performing Extra Work Before or After Retrieving an Object

Sometimes you need to perform additional actions when retrieving an object. For example, imagine tracking when an author’s page was last accessed.

Model with a last_accessed Field


class Author(models.Model):
    name = models.CharField(max_length=200)
    last_accessed = models.DateTimeField()

URL Pattern for Author Details


path("authors/<int:pk>/", AuthorDetailView.as_view(), name="author-detail"),

Overriding get_object() to Update last_accessed


class AuthorDetailView(DetailView):
    queryset = Author.objects.all()

    def get_object(self):
        obj = super().get_object()
        obj.last_accessed = timezone.now()
        obj.save()
        return obj

Note: DetailView uses pk by default to look up the object. If your URL uses a different parameter name, set pk_url_kwarg.


Conclusion

By customizing the queryset, overriding get_queryset(), adding extra context, and extending get_object(), you gain full control over how Django’s generic views retrieve and display data. These techniques allow you to build dynamic, flexible, and highly maintainable views with minimal boilerplate.

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