Django same slug but using different URL path
I am making a documentation site to self-host for myself; learning Django at the same time. I am at the point where I am starting to populate the website.
I am wondering if there is a possibility to have two posts that have the same slug, but they are part of a different category.
For example, I have two posts that are named "virus". One is under the category of "computer science" and the other is under the category of "heathcare".
The website would link those pages as:
.../healthcare/virus/
.../computer-science/virus/
Is there a way to use the same slug depending on the value of another field (e.g. category field) or some other technique?
TIA
You can have duplicate slugs as long as they are are unique within their respective categories. The best way to handle this in Django is by enforcing uniqueness at the database level using the unique_together
constraint.
You can eventually override the save()
method to automatically generate slugs if duplicates exist:
from django.db import models
from django.utils.text import slugify
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(unique=True)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=255)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
slug = models.SlugField(max_length=255)
# Other fields ...
class Meta:
# Your Meta here ...
constraints = [
models.UniqueConstraint(fields=['slug', 'category'], name='unique_slug_per_category')
]
def save(self, *args, **kwargs):
# Generate a slug if it's not set
if not self.slug:
base_slug = slugify(self.title)
self.slug = base_slug
count = 1
while Post.objects.filter(slug=self.slug, category=self.category).exists():
self.slug = f"{base_slug}-{count}"
count += 1
super().save(*args, **kwargs)
def __str__(self):
return f"{self.category.name} - {self.title}"
In this way each Post is linked to a Category, while the Unique Constraint ensures that the same slug cannot be repeated within the same category. Finally, the save()
method generates a slug from the title if it’s not provided (it also checks if a duplicate exists, appending a number (slug-1, slug-2, etc.) to make it unique).
URLs can be defined like:
urlpatterns = [
path('<slug:category_slug>/<slug:slug>/', YourView.as_view(), name='post-detail'),
]
Hope it helped