Previous and Next Link to Adjacent Records in Django DetailView

How to provide previous and next links to adjacent records in DetailView
July 29, 2024 by
Previous and Next Link to Adjacent Records in Django DetailView
Hamed Mohammadi
| No comments yet

Django's generic class-based views offer a streamlined approach to common view patterns. For instance, DetailView simplifies displaying individual model records. This post demonstrates how to extend DetailView's functionality by incorporating links to adjacent records.

To illustrate the concept effectively, we'll use a simple model equipped with a get_absolute_url method. This method is essential for generating correct URLs within our template.

 

from django.db import models
from django.conf import settings
from django.urls import reverse
from django.utils import timezone

User = settings.AUTH_USER_MODEL

# Create your models here.


class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    text = models.TextField(max_length=500)
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return f"{self.user}: {self.text}"

    def get_absolute_url(self):
        return reverse("feed:post_detail", kwargs={"pk": self.pk})

To enrich the detail view with previous and next record links, we dynamically populate the context with this information in our detail view as demonstrated in the code snippet. 

class PostDetailView(DetailView):
    model = Post
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["previous"] = self.get_previous_object()
        print(self.get_previous_object())
        context["next"] = self.get_next_object()
        return context

    def get_previous_object(self):
        return (
            self.model.objects.filter(created_at__lt=self.object.created_at)
            .order_by("-created_at")
            .first()
        )

    def get_next_object(self):
        return (
            self.model.objects.filter(created_at__gt=self.object.created_at)
            .order_by("created_at")
            .first()
        )

Lastly, we leverage these context variables within our template to render the desired links, as illustrated in the subsequent code example. 

{% extends 'base.html' %}

{% block content %}
  <div class="container mt-5">
    <div class="card">
      <div class="card-body">
        <h1 class="card-title">Posted by {{ post.user }} on {{ post.created_at }}</h1>
        <p class="card-text">{{ post.text|linebreaks }}</p>
      </div>
    </div>
    <div class="row">
      <div class="btn-group">
        <a href="{% url 'feed:post_list' %}" class="btn btn-primary mx-1">Back to Post List</a>
        {% if previous %}
          <a href="{{ previous.get_absolute_url }}" class="btn btn-primary mx-1">Previous</a>
        {% endif %}
        {% if next %}
          <a href="{{ next.get_absolute_url }}" class="btn btn-primary mx-1">Next</a>
        {% endif %}
      </div>
    </div>
  </div>
{% endblock %}

The end result is a detail page that seamlessly integrates links to both the preceding and subsequent records, as visually depicted in the screenshot.

 

While this approach effectively adds previous and next links, it's important to note a potential performance bottleneck. Executing two additional database queries for each page view can significantly impact response times, especially on high-traffic sites.

To optimize performance, consider alternative strategies such as prefetching related objects, utilizing querysets efficiently, or employing caching mechanisms.

What do you suggest as a more efficient method?

 

Previous and Next Link to Adjacent Records in Django DetailView
Hamed Mohammadi July 29, 2024
Share this post
Archive

Please visit our blog at:

https://zehabsd.com/blog

A platform for Flash Stories:

https://readflashy.com

A platform for Persian Literature Lovers:

https://sarayesokhan.com

Sign in to leave a comment