Reputation: 902
I have three models Book
, Part
, Chapter
, in my models.py
that uses the SlugField
.
For the Book
class, I have written a slug handler in the custom save
method that checks if an object exists with the slug
. And when it does, it makes it unique by appending a count
to it.
How do I rewrite the block inside Book
's to SlugMixin
so that I can use for the rest of the models?
models.py
...
class SlugMixin(models.Model):
slug = models.SlugField(max_length=50, unique=True)
class Meta:
abstract = True
class Book(models.Model):
title = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
def save(self, *args, **kwargs):
if not self.pk and not self.slug:
slug = slugify(self.title, allow_unicode=True)
slug_exists = True
counter = 1
self.slug = slug
while slug_exists:
try:
slug_exists = Book.objects.get(slug=slug)
if slug_exists:
slug = self.slug + '_' + str(counter)
counter += 1
except Book.DoesNotExist:
self.slug=slug
break
class Part(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='parts')
title = models.CharField(max_length=30)
slug = models.SlugField(max_length=30, unique=True)
class Chapter(models.Model):
part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='chapters')
title = models.CharField(max_length=40)
slug = models.SlugField(max_length=40, unique=True)
...
Upvotes: 0
Views: 335
Reputation: 21
Instead of doing this implementation yourself, you can use the autoslug library instead.
Install pip install django-autoslug
and in your model you can define the AutoSlugField
field like this:
# models.py
...
from autoslug import AutoSlugField
...
class YourModel(models.Model):
...
name = models.CharField(max_length=50)
slug = AutoSlugField(populate_from="name", unique=True, max_length=50, db_index=True)
...
Upvotes: 0
Reputation: 88519
How about this
SLUG_LENGTH = 50
def get_unique_slug(model_instance):
slugify_title = slugify(model_instance.title, allow_unicode=True)
if len(slugify_title) > SLUG_LENGTH:
slug = slugify_title[:SLUG_LENGTH]
else:
slug = slugify_title
slug_copy = slug
num = 1
while model_instance.__class__.objects.filter(slug=slug).exists():
number_attached_slug = '{}-{}'.format(slug_copy, num)
if len(number_attached_slug) > SLUG_LENGTH:
trimmed_slug = slug_copy[:-(num + 1)] # adding 1 because there is hyphen in the slug
slug = '{}-{}'.format(trimmed_slug, num)
else:
slug = number_attached_slug
num += 1
return slug
class SomeLogicKlass:
def save(self, *args, **kwargs):
if not self.slug:
self.slug = get_unique_slug(self)
super().save(*args, **kwargs)
def __str__(self):
return self.slug
class Book(SomeLogicKlass, models.Model):
...
class Part(SomeLogicKlass, models.Model):
...
Note: make sure the value of SLUG_LENGTH
is same as the max_length
of models.SlugField(...)
Upvotes: 1