Django уникальное поле slug для двух или более моделей

У меня есть такая структура:

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)

Я создал одну категорию с меткой "test". Когда я пытаюсь создать новую категорию с меткой "test", я получаю предупреждение, но это нормально. Но если я пытаюсь создать продукт с slug "test", я не получаю предупреждения, и это не очень хорошо в моем случае. Есть ли решение или метод для проверки поля slug на уникальность в модели продукта и категории?

Вы можете переписать метод сохранения для каждого, а затем проверить, существует ли уже данный slug для товара или категории.

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)


Идея может заключаться в создании модели Slug, которая хранит все слизни, опционально с обратной ссылкой на объект:

class Slug(models.Model):
    slug = models.SlugField(max_length=255, primary_key=True)

Тогда слизни в ваших моделях ForeignKey относятся к этой модели Slug, и вы проверяете, существует ли такой слизень уже:

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)

При этом часто допускается перекрытие слогов для различных типов сущностей.

Вернуться на верх