I have such structure:
class Category(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
parent = models.ForeignKey('self', blank=True, null=True,
related_name='children',
on_delete=models.CASCADE
)
slug = models.SlugField(max_length=255, null=False, unique=True)
class Product(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
to_category = models.ForeignKey(Category, on_delete=models.SET_NULL,
blank=True, null=True,
)
slug = models.SlugField(max_length=255, null=False, unique=True)
I have created one category with slug "test". When I try to create new category with slug "test" I got warning message and it is Ok. But If I try to create product with slug "test" I dont have warning and this is not good in my case. Is there a solution or method to validate slug field for uniqueness with Product and Category model?
CodePudding user response:
You can override the save method for each, and then check if the given slug already exists for a product or category.
def is_slug_unique(slug):
product_exists = Product.objects.filter(slug=slug).exists()
category_exists = Category.objects.filter(slug=slug).exists()
if product_exists or category_exists:
return False
else:
return True
class Category(models.Model)
...
def save(self, *args, **kwargs):
slug_unique = is_slug_unique(self.slug)
if not slug_unique:
# do something when the slug is not unique
else:
# do something when the slug is unique
super().save(*args, **kwargs)
class Product(models.Model)
...
def save(self, *args, **kwargs):
slug_unique = is_slug_unique(self.slug)
if not slug_unique:
# do something when the slug is not unique
else:
# do something when the slug is unique
super().save(*args, **kwargs)
CodePudding user response:
An idea might be to create a Slug
model that stores all the slugs, optionally with a backreference to the object:
class Slug(models.Model):
slug = models.SlugField(max_length=255, primary_key=True)
Then the slugs in your models are ForeignKey
s to that Slug
model, and you check if such slug already exists:
from django.core.exceptions import ValidationError
class Product(models.Model):
name = models.CharField(max_length=255, validators=[MinLengthValidator(3)])
to_category = models.ForeignKey(
Category, on_delete=models.SET_NULL, blank=True, null=True
)
slug = models.ForeignKey(Slug, on_delete=models.PROTECT)
def validate_slug(self):
if self.pk is not None and Slug.objects.filter(pk=self.slug_id).exclude(
product__pk=self.pk
):
raise ValidationError('The slug is already used.')
def clean(self, *args, **kwargs):
self.validate_slug()
return super().clean(*args, **kwargs)
def save(self, *args, **kwargs):
self.validate_slug()
return super().save(*args, **kwargs)
That being said, often overlapping slugs for different entity types are allowed.