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"