
روز ۳۴: پیادهسازی Pagination و جستجو در جنگو
در هر پروژه واقعی جنگو که با لیستی از دادهها سروکار دارد، خیلی زود با یک مشکل اساسی مواجه میشویم: حجم زیاد اطلاعات. نمایش صدها یا هزاران رکورد در یک صفحه هم تجربه کاربری را خراب میکند و هم فشار زیادی به سرور وارد میسازد. Pagination یا صفحهبندی دقیقاً برای حل همین مشکل به وجود آمده است. از طرف دیگر، جستجو یکی از مهمترین قابلیتهایی است که کاربران انتظار دارند تا سریعتر به داده مورد نظرشان برسند. ترکیب Pagination و Search باعث میشود پروژه شما حرفهایتر، سریعتر و کاربرپسندتر به نظر برسد.
مفهوم Pagination در جنگو به زبان ساده
Pagination یعنی تقسیم دادهها به صفحات کوچکتر و قابل مدیریت. به جای نمایش همه آیتمها در یک صفحه، دادهها به چند صفحه تقسیم میشوند و کاربر میتواند بین آنها جابهجا شود. جنگو ابزار داخلی بسیار قدرتمندی برای این کار دارد که بدون نیاز به کتابخانه خارجی قابل استفاده است. استفاده از Pagination استاندارد جنگو نهتنها باعث کاهش حجم کد میشود، بلکه از نظر عملکرد نیز بسیار بهینه است و در پروژههای بزرگ کاملاً جواب میدهد.
استفاده از Pagination در Function Based View
اگر از Function Based View استفاده میکنید، کلاس Paginator سادهترین راه برای پیادهسازی صفحهبندی است. در این روش ابتدا QuerySet را دریافت میکنیم و سپس آن را به Paginator میدهیم تا دادهها به صفحات مشخص تقسیم شوند. این ساختار انعطافپذیر است و کنترل کاملی روی تعداد آیتمها در هر صفحه به شما میدهد.
from django.core.paginator import Paginator
from .models import Article
def article_list(request):
articles = Article.objects.all()
paginator = Paginator(articles, 5)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'articles/list.html', {'page_obj': page_obj})در این مثال، هر صفحه شامل ۵ مقاله خواهد بود و جنگو به صورت خودکار مدیریت صفحات نامعتبر را انجام میدهد.
نمایش Pagination در Template
پس از پیادهسازی Pagination در View، باید لینکهای صفحهبندی را در Template نمایش دهیم. جنگو این کار را بسیار ساده کرده و اطلاعات کاملی درباره صفحه فعلی، صفحه قبل و صفحه بعد در اختیار ما قرار میدهد. نمایش درست Pagination تأثیر زیادی روی تجربه کاربری دارد و نباید آن را ساده یا ناقص پیادهسازی کرد.
{% for article in page_obj %}
<h2>{{ article.title }}</h2>
{% endfor %}
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">قبلی</a>
{% endif %}
<span>صفحه {{ page_obj.number }} از {{ page_obj.paginator.num_pages }}</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">بعدی</a>
{% endif %}این ساختار پایهای است و بهراحتی میتوان آن را با CSS زیباتر کرد.
Pagination در Class Based View
در Class Based View پیادهسازی Pagination حتی سادهتر هم میشود. کافی است از ListView استفاده کنیم و مقدار paginate_by را مشخص کنیم. جنگو به صورت خودکار تمام منطق صفحهبندی را برای ما انجام میدهد و دادهها را به Template ارسال میکند.
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article
template_name = 'articles/list.html'
paginate_by = 5این یکی از بزرگترین مزایای CBV است و باعث میشود کد بسیار تمیز و قابل نگهداری باقی بماند.
مفهوم جستجو در جنگو
جستجو در جنگو معمولاً با فیلتر کردن QuerySet انجام میشود. یعنی بر اساس دادهای که کاربر وارد میکند، نتایج محدود میشوند. این کار میتواند روی عنوان، متن یا هر فیلد دیگری انجام شود. پیادهسازی جستجو اگر درست انجام شود، هم سریع است و هم فشار زیادی به دیتابیس وارد نمیکند. استفاده از lookupهایی مانند icontains باعث میشود جستجو به صورت غیرحساس به حروف بزرگ و کوچک انجام شود.
پیادهسازی جستجو در View
برای پیادهسازی جستجو، معمولاً مقدار ورودی کاربر از طریق GET دریافت میشود. سپس بر اساس آن QuerySet فیلتر میشود. این روش ساده اما بسیار کاربردی است و در اکثر پروژههای جنگو مورد استفاده قرار میگیرد.
def article_list(request):
query = request.GET.get('q')
articles = Article.objects.all()
if query:
articles = articles.filter(title__icontains=query)در این مثال، فقط مقالاتی نمایش داده میشوند که عنوان آنها شامل عبارت جستجو شده باشد.
ترکیب Pagination و جستجو
یکی از نکات مهم این است که Pagination و جستجو باید با هم سازگار باشند. یعنی وقتی کاربر جستجو میکند و به صفحه دوم میرود، عبارت جستجو نباید از بین برود. این موضوع با ارسال پارامترهای GET در لینکهای Pagination حل میشود و باعث میشود تجربه کاربری بسیار بهتری ایجاد شود.
<a href="?q={{ request.GET.q }}&page={{ page_obj.next_page_number }}">بعدی</a>این کار باعث میشود جستجو در تمام صفحات حفظ شود.
جستجو در Class Based View
در CBV میتوان متد get_queryset را بازنویسی کرد و منطق جستجو را در آن پیادهسازی نمود. این روش بسیار تمیز و حرفهای است و برای پروژههای بزرگ توصیه میشود.
class ArticleListView(ListView):
model = Article
paginate_by = 5
def get_queryset(self):
queryset = super().get_queryset()
query = self.request.GET.get('q')
if query:
queryset = queryset.filter(title__icontains=query)
return querysetاین ساختار یکی از بهترین روشها برای ترکیب جستجو و Pagination در جنگو است.
نکات مهم برای بهینهسازی سئو
Pagination و جستجو اگر درست پیادهسازی نشوند، میتوانند به سئو سایت آسیب بزنند. استفاده از URLهای تمیز، جلوگیری از محتوای تکراری و توجه به ساختار لینکها اهمیت زیادی دارد. همچنین بهتر است صفحات Pagination دارای عنوان و توضیحات متای مناسب باشند تا موتورهای جستجو بتوانند آنها را به درستی ایندکس کنند.
جمعبندی روز سیوچهارم
در روز سیوچهارم یاد گرفتیم چگونه Pagination و جستجو را در جنگو پیادهسازی کنیم، هم با Function Based View و هم با Class Based View. این دو قابلیت از مهمترین بخشهای هر پروژه واقعی هستند و نقش مستقیمی در تجربه کاربری و عملکرد سایت دارند. تسلط بر Pagination و Search شما را یک قدم دیگر به سطح حرفهای جنگو نزدیک میکند.