pythondjangomezzaninedjango-oscardjango-modeltranslation

Using Django-ModelTranslation with Django-Oscar, but "No new translatable fields detected"


I'm trying to use Django-ModelTranslation (0.12.2) to provide translation fields for products in Django-Oscar (1.5.2). It uses Django 1.10.8. I followed the documentation on Registering Models for Translation but keep getting this in response: No new translatable fields detected.

I don't know if this might be part of the problem but I first started a Mezzanine (4.2.3) project and then integrated Oscar into it using Oscar's docs. Translation fields were added to Mezzanine perfectly. (EDIT: added Oscar with ModelTranslation to a new Django project, same response, so it's not Mezzanine.)

Below, I show how I forked Oscar's catalogue app and added it to settings.py.

project/settings.py:

from oscar import get_core_apps


# Django-ModelTranslation settings

USE_MODELTRANSLATION = True
MODELTRANSLATION_FALLBACK_LANGUAGES = ('en',)

LANGUAGES = (
    ('en', _('English')),
    ('de', _('German')),
)


INSTALLED_APPS = [
    ...,
] + get_core_apps(['forked_apps.catalogue'])

project/forked_apps/catalogue/translation.py:

from modeltranslation.translator import translator, TranslationOptions
from oscar.apps.catalogue.abstract_models import AbstractProduct

class AbstractProductTranslationOptions(TranslationOptions):
    fields = ('title', 'description',)

translator.register(AbstractProduct, AbstractProductTranslationOptions)

I then ran sync_translation_fields to no avail. What have I missed?


Solution

  • So, I pressed CTRL+SHIFT+R on PyCharm, entered the No new translatable fields detected response into it and searched the ModelTranslation package for where it comes from. I found it in modeltranslation.management.commands.sync_translation_fields.Command. This is a class containing a handle() with this line: models = translator.get_registered_models(abstract=False).

    I thought, ok, maybe it's not working because oscar.apps.catalogue.abstract_models.AbstractProduct has abstract=True. I guess the dead giveaway is in the name of the module itself.

    So, if it's not AbstractProduct, where's the right model? I decided to try triggering another error to figure it out. I overrode Oscar's abstract_models.AbstractProduct with my own in project.catalogue.abstract_models:

    from django.db import models
    from django.utils.translation import get_language, pgettext_lazy
    from django.utils.translation import ugettext_lazy as _
    
    from oscar.apps.catalogue.abstract_models import AbstractProduct
    
    class AbstractProduct(AbstractProduct):
        title = models.CharField(pgettext_lazy(u'Product title', u'Title'),
                                 max_length=255, blank=True)
        description = models.TextField(_('Description'), blank=True)
    
    from oscar.apps.catalogue.models import *
    

    It produced this error:

    ERRORS:
    catalogue.AbstractProduct.product_class: (fields.E304) Reverse accessor for 'AbstractProduct.product_class' clashes with reverse accessor for 'Product.product_class'.
    ...
    

    It goes on for 20+ lines but the first was enough. The correct model was Product. So, I went hunting again and found it in oscar.apps.catalogue.models.Product. No surprise, it looked like this: Product(AbstractProduct).

    Only two things left to do. First, I edited my translation.py in project.forked_apps.catalogue:

    from modeltranslation.translator import register, translator, TranslationOptions
    # DELETED: from oscar.apps.catalogue.abstract_models import AbstractProduct
    from oscar.apps.catalogue.models import Product
    
    # Updated the following accordingly.
    class ProductTranslationOptions(TranslationOptions):
        fields = ('title', 'description',)
    
    translator.register(Product, ProductTranslationOptions)
    

    Second, I ran python manage.py sync_translation_fields. It worked!

    Now, on to whatever the next problem is.