pythondjangotranslationslug

Saving translated slug of django modeltranslation not working


I've been breaking my head over this for a day now.

I use django-modeltranslation to translate blog-like posts. All works fine, except I also try to automatically translate the slugs from the title, based off of this article: https://raphaelbeck.wordpress.com/2011/04/16/how-to-translate-slug-with-django-modeltranslation/

Only the translated slug is not translated saved to the database.

class Item(models.Model):
    category = models.ForeignKey(
        'help.category',
        on_delete=models.PROTECT,
        related_name='categories')
    title = models.CharField(_('Titel'),max_length=255)
    description = RichTextField(_('Omschrijving'))
    slug = AutoSlugField(_('slug'), populate_from='title', overwrite=True)

    class Meta:
        verbose_name = _(u"Item") 
        verbose_name_plural = _(u"Items")

        #automatically creating slugs for translations
    def save(self, *args, **kwargs):
        for lang_code, lang_verbose in settings.LANGUAGES:
            if hasattr(self, 'slug_%s' % lang_code) and hasattr(self, 'title_%s' % lang_code):
                setattr(self, 'slug_%s' % lang_code, slugify(getattr(self, 'title_%s' % lang_code, u"")))
            print(self.slug_nl)
            print(self.slug_en)

        print(self.slug_nl)
        print(self.slug_en)
        super().save(*args, **kwargs)

    def __str__(self):
        return str(self.title)

I added some print funtions to see what actually happens. The console logs are as expected:

dutch-slug

None

dutch-slug

english-slug

dutch-slug

english-slug

-> slug_en is translated correctly based on the title in the console, but in the database the dutch slugs are saved.

Thanks in advance! Any ideas are greatly appreciated.


Solution

  • django-model-translation and AutoSlugField perform what they need to do during the save() method, so what you do prior to saving is overwritten later.

    There's no other way than to add the translations post-save, even if that means saving the model twice. Also you can't call save() in post_save otherwise you create an endless recursion. Use update() on the queryset. Write a post_save signal handler:

    @receiver(post_save, sender=Item)
    def add_slug_translations(instance, **kwargs):
        attrs = {}
        for lang_code, lang_verbose in settings.LANGUAGES:
            if hasattr(self, 'slug_%s' % lang_code) and hasattr(self, 'title_%s' % lang_code) and getattr(self, 'title_%s' % lang_code):
                attrs.update({'slug_%s' % lang_code: slugify(getattr(self, 'title_%s' % lang_code, u"")})
        if attrs:
            Item.objects.filter(id=instance.id).update(**attrs)