Slug создан некорректно из-за использования django parler

У меня проблема с созданием slug на основе заголовка и pk из-за использования parler. Я использую Parler для многоязычия в моем API, и когда я пытаюсь создать slug, подобный title-pk Я получаю различные ошибки. Моя модель:

class Events(TranslatableModel):
    ...
    translations = TranslatedFields(
        title=models.CharField(max_length=255, verbose_name=_("Event title")),
        body=MDTextField(verbose_name=_("Event body")),
    )
    slug = models.SlugField(blank=True, max_length=255, verbose_name=_("Event slug"))
    ...

Итак, я попытался использовать метод save(), но получил ошибку типа -None или -pk.

    def save(self, *args, **kwargs):
        if not self.slug:
            title = self.safe_translation_getter("title", language_code="uk")
            base_slug = slugify(title)
            self.slug = f"{base_slug}-{self.pk}"
        super().save(*args, **kwargs)

Я также использовал сигнал , который также не сработал.

@receiver(post_save, sender=Events)
def generate_slug_after_translation(sender, instance, **kwargs):
    if not instance.slug:
        uk_title = instance.safe_translation_getter("title", language_code="uk")
        if uk_title:
            base_slug = f"{uk_title}-{instance.pk}"
            instance.slug = slugify(base_slug)[:255]
            instance.save(update_fields=["slug"])

Что я сделал не так и что мне делать дальше?

Спасибо за предложение в комментариях — отладка помогла мне найти проблему.
Итак, в чем проблема. Метод save() не сгенерировал slug правильно, потому что он выполнялся до того, как объект был сохранен в базе данных, что означает, что pk был None а существование переведенного title еще не было гарантировано.
Я попытался вызвать super().save(*args, **kwargs), прежде чем получить доступ к переведенному title, вот так:

def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.slug:
            title = self.safe_translation_getter("title", language_code="uk")
            base_slug = slugify(title)
            logging.debug(f"[DEBUG] Event base_slug: {base_slug}")
            self.slug = f"{base_slug}-{self.pk}"
            logging.debug(f"[DEBUG] Event slug: {self.slug}")
        super().save(*args, **kwargs)

Но логи показали следующее:


[DEBUG] Event base_slug:
[DEBUG] Event slug: -9

Который подтвердил, что title все еще пуст.

Рабочее решение: использовать сигнал post_save
Я нашел причину проблемы: сгенерированный фрагмент кода был некорректным при использовании кириллических символов.
Мой предыдущий сигнал выдал следующие логи:


[DEBUG] base_slug: тест-11
[DEBUG] instance.slug: 11

Оказывается, slugify() по умолчанию не транслитерирует символы, отличные от ASCII.
Я установил unidecode и использовал его для транслитерации базовой строки перед передачей ее в slugify():

from unidecode import unidecode

@receiver(post_save, sender=Event)
def generate_slug_after_translation(sender, instance, **kwargs):
    if not instance.slug:
        uk_title = instance.safe_translation_getter("title", language_code="uk")
        if uk_title:
            base_slug = f"{uk_title}-{instance.pk}"
            slug = slugify(unidecode(base_slug))[:255]
            logging.debug(f"[DEBUG] instance.slug: {slug}")
            instance.slug = slug
            instance.save(update_fields=["slug"])

Теперь кириллический заголовок в slug корректно транслитерируется латинскими буквами: "тест-11" → "test-11"

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