~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_listpublisher_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.
نوشته و پژوهش شده توسط دکتر شاهین صیامی