Search code examples
djangodjango-modelstranslationsignalsdjango-signals

Multiple post_save signals causing slugify issues with translated model


I'm currently working with django-nani to enable translated models on a project.

Many of these models require slugs for URL generation. My client is non-technical, and asking them to enter slugs would be unreasonable in terms of both expectations and support costs. Translation is a new requirement, so I am working to adjust old models for translation.

When saving a model, nani registers a post_save signal for the purpose of saving translations. This is fine, except that now if I attempt to register a post_save signal to use said translations to generate slugs, I'm out of luck; either my signal is running after or concurrently and no translation object exists.

The offending model code:

from django.db import models
from django.db.models import signals
from django.template.defaultfilters import slugify

from tinymce.models import HTMLField
from nani.models import TranslatableModel, TranslatedFields

class Product(TranslatableModel):
    translations = TranslatedFields(
        name = models.CharField(max_length=100),
        title = models.CharField(max_length=100),
        description = HTMLField(),
    )

    slug = models.SlugField(max_length=100, blank=True, null=True, editable=False),

    # Various unrelated fields...

    def __unicode__(self):
        return self.translations.get(language_code='en').name

def product_post_save(sender, instance, created, **kwargs):
    new_slug = slugify(instance.translations.get(language_code='en').name)

    if instance.slug != new_slug:
        instance.slug = new_slug
        instance.save()
signals.post_save.connect(product_post_save, Product)

This causes a ProductTranslation matching query does not exist DoesNotExist exception on the first line of product_post_save.

I've briefly tried refactoring nani to override the save method instead of using post_save, but that seems to be a nontrivial task (at least for someone who knows little about its internals, like me).

I've looked at some third-party autoslug fields, but I can't imagine any would work with this particular situation and translation library.

My questions would be...

  • Is there a way to make sure one post_save is lined up after any others that are defined?
  • Barring that, can anyone else suggest a different/better solution to this issue?

Edit: Found out signal priority has been suggested and shot down by the Django core devs.


Solution

  • Since the Django team has elected not to support ordering for methods registered on hooks and nani implements translation save using them, I found no clear way to make sure my code ran after nani's post_save methods.

    In the end I forked nani and added a custom signal that fires when its post_save finishes. It's not ideal (in my opinion), but it works.