Django pagination of filtered post list

34 Views Asked by At

I've been working on a project of a blog where all posts are grouped by rubrics. The posts can be filtered by rubric in the frontend but I've got some problems whith implementing pagination. Paginator works fine and paginates filtered list, when I choose a rubric on my site it shows the number of pages and shows link to the next. But the url it forms ignores rubrication and instead of sending me to something like localhost/blog/?rubric=some_rubric&page=2 it shows localhost/blog/?page=2 The pagination works fine if I input adress by hand.

models.py

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from taggit.managers import TaggableManager

class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset()\
                      .filter(status=Post.Status.PUBLISHED)

class Rubric(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField()

    class Meta:
        verbose_name_plural = 'Rubrics'
        ordering = ('name',)
        indexes = [models.Index(fields=['name']),]
    
    def __str__(self):
        return self.name

class Post(models.Model):

    class Status(models.TextChoices):
        DRAFT = 'DF', 'Draft'
        PUBLISHED = 'PB', 'Published'

    title = models.CharField(max_length=250)
    slug = models.SlugField(max_length=250, unique_for_date='publish')
    cover_img = models.ImageField(upload_to='post_covers/', blank=True, null=True)
    rubric = models.ForeignKey(Rubric, on_delete=models.CASCADE, related_name='posts')
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
    excerpt = models.TextField(max_length=500)
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=2, choices=Status.choices, default=Status.DRAFT)

    objects = models.Manager() # The default manager.
    published = PublishedManager() # Our custom manager.
    tags = TaggableManager()

    class Meta:
        ordering = ['-publish']
        indexes = [
            models.Index(fields=['-publish']),
        ]

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blog:post_detail',
                       args=[self.publish.year,
                             self.publish.month,
                             self.publish.day,
                             self.slug])

view.py

from django.shortcuts import render
from .models import Post, Rubric
from django.utils import timezone
from django.views.generic.detail import DetailView
from django.core.paginator import Paginator

def post_list(request):
    post_list = Post.published.all()
    rubrics = Rubric.objects.all()    

    active_rubric = request.GET.get('rubric', '')
    if active_rubric:
        post_list = post_list.filter(rubric__slug=active_rubric)

    paginator = Paginator(post_list, 3)
    page_number = request.GET.get('page', 1)
    posts = paginator.page(page_number)
    
    context = {
        'posts': posts,
        'rubrics': rubrics,
        'active_rubric': active_rubric,
    }

    return render(request, 'blog.html', context)

class PostDetailView(DetailView):
    model = Post
    template_name = 'post_detail.html'

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

urls.py

from django.urls import path

from blog.views import post_list, PostDetailView

urlpatterns = [
    path('', post_list, name='blog'),
    path('<slug:slug>/', PostDetailView.as_view(), name='post-detail'),

]

blog.html Here I insert pagination through include tag:

{% include 'pagination.html' with page=posts %}

pagination.html

<div class="pagination">
    <span class="step-links">
        {% if page.has_previous %}
            {% if rubric.slug == active_rubric %}
                <a href="?rubric={{ rubric.slug }}&page={{ page.previous_page_number }}">Previous</a>
            {% else %}
                <a href="?page={{ page.previous_page_number }}">Previous</a>
            {% endif %}
        {% endif %}
    <span>
        Page{{ page.number }} of {{ page.paginator.num_pages }}
    </span>
        {% if page.has_next %}
            {% if rubric.slug == active_rubric %}
                <a href="?rubric={{ rubric.slug }}&page={{ page.next_page_number }}">Next</a>
            {% else %}
                <a href="?page={{ page.next_page_number }}">Next</a>
            {% endif %}
        {% endif %}
    </span>
</div>

I suspect that my pagination template cannot access rubric slug and active_rubric variables but I can't figure out how to make it see them.

0

There are 0 best solutions below