deschler / django-modeltranslation

Translates Django models using a registration approach.
BSD 3-Clause "New" or "Revised" License
1.37k stars 258 forks source link

model-translation doesn’t work with related tables #675

Open ruchika2012 opened 1 year ago

ruchika2012 commented 1 year ago

Model-translation works well when i want to access column of the same model. But when it comes to relationship, it doesn’t work always give you the original model field and not the translated model field Example (code snippet from views.py (method= GET))

queryset = Audit.objects.all().annotate(
            areaName=F("formFK__parentFK__tableFK__areaFK__name"))

name is a translated field in the area table, so it has 'name', 'name-es' and 'name-fr' columns since my translated languages are FR & ES

In this scenario, we are trying to access areaName via chaining through formFK. In this case the areaName gives the value from 'name' column instead of 'name-es', 'name-fr' (even when my current language is set either of es and fr)

It works fine when there's no relationship. Like if I have to read a translated field from Audit, it will read from corresponding column (created for that language).

Any ideas on how we can make GET work even if we are querying into related tables?

last-partizan commented 1 year ago

You can look at https://github.com/deschler/django-modeltranslation/blob/master/modeltranslation/manager.py

I can see some code that looks like it should support translating related tables, but it it doesn't, create test case reproducing an issue, and then try to fix it.

ryselis commented 7 months ago

I have looked into the problem. In this case, Audit class is not registered for translations and does not use the translation queryset, and no field rewrites are performed. I see no other solution than to add translation queryset (or a different variant of it) for all related model hierarchy. Is this the approach we should go for?

last-partizan commented 7 months ago

Looks reasonable enough, yes.

ryselis commented 7 months ago

I don't think this should be closed yet - we will need a fix :)

last-partizan commented 7 months ago

Ok, leaving it open then.

But, preferable way to go - is to implement custom QuerySet yourself, test it for a few month, and if you think it's reasonably good - create PR.

ryselis commented 7 months ago

I have implemented a custom queryset that handles only filtering as this was the problem for my application. The approach is to add a lazy operation to the translator that gets all non-registered models and registers the patched querysets with all the code copy-pasted from this library to handle only filter (_filter_or_exclude with all the dependencies). I will ship it to production and if all goes well, will maybe create a PR.

I don't see a better solution as the queries are generated inside of a queryset, so we need to patch it somehow, even though the model itself is not translatable.

last-partizan commented 7 months ago

The approach is to add a lazy operation to the translator that gets all non-registered models and registers the patched querysets

Why do you need to register all models?

Maybe, it would be better to specify manager explicitly where it's needed?

Something like

class Audit(...):
    objects = RecursiveModelTranslationManager()
ryselis commented 7 months ago

This works very weird with Django admin. I have two models - Good (has translatable title) and Balance (has a FK to Good). If I add title to GoodAdmin.search_fields, it searches by translated title. If I add good__title to BalanceAdmin.search_fields, it does not work with translated fields. It would still work in one language, making it more difficult to catch for QA. I think this is very error prone because it works differently from seemingly identical scenarios. Also if I do not have a translated field on Good and decide to make a field translatable later, there is no good way to find all models where I need this, and if I miss one, it will work inconsistently. Now add all possible ways to utilize this - annotate, order by etc. - it's almost impossible to catch all cases in a large application, especially when you have a long chain of FK fields, inherited models etc.