moddayjob
moddayjob

Reputation: 708

Django - How to query a related translated model?

I have two models that are many to many related. Article and Tag models. Both are TranslateableModel using django-parler.

models.py

class Article(BaseModelMixin, TranslatableModel):
    translations = TranslatedFields(
        title=models.CharField(max_length=255),
        short_description=models.CharField(max_length=255),
        body=HTMLField(),
        slug=models.SlugField(max_length=255, blank=True, null=True, unique=True),
    ),
    tags = models.ManyToManyField("Tag", related_name="articles")


class Tag(TranslatableModel):
    translations = TranslatedFields(
        slug=models.SlugField(max_length=55, blank=True, null=True),
        name=models.CharField(_("Tag name"), max_length=50),
    )

I would like to get all tags together with articles_count for the current language.

For example if a user comes to the page /en/blog I would like them to see tags together with the number of articles written in english for that tag. Something like Django (7 articles), Ruby on rails (4 articles) For django there might be 10 articles but only 7 are translated to english.

What I have is something like this:

Tag.objects.translated()
           .annotate(articles_count=(Count("articles__translations")))

But this gives me the count of total translations. If an article exists both in english and in french, it counts double.

How can I make it so that it gives me the number of articles only in the current language in a given tag?

Upvotes: 1

Views: 1407

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477265

You can filter on the language_code, so:

from django.utils.translation import get_language

language = get_language()

Tag.objects.annotate(
    articles_count=Count(
        'articles__translations', 
        filter=Q(articles__translations__language_code__iexact=language)
    )
)

This will only retain articless with the exact same language code. This thus means that if the language is en-US, it will not consider en to be valid.

You can retain only the language and not the country, and then filter with:

# culture-invariant languages

from django.utils.translation import get_language

language = get_language().split('-', 1)[0]

Tag.objects.annotate(
    articles_count=Count(
        'articles__translations', 
        filter=Q(articles__translations__language_code__istartswith=language)
    )
)

Upvotes: 3

Related Questions