Django queryset show english translations

Question:

This is my Django models.py:

from django.db import models


class Blog(models.Model):
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.pub_date

class LanguagesCode(models.Model):
    code = models.CharField(max_length=5)

    def __str__(self):
        return self.code

class BlogTranslation(models.Model):
    name = models.CharField(max_length=250)
    content = models.TextField(blank=True, null=True)
    blog_id = models.ForeignKey(Blog, related_name='translations', on_delete=models.CASCADE)
    language_code = models.ForeignKey(LanguagesCode, related_name='languages', on_delete=models.DO_NOTHING)

    class Meta:
        unique_together = ('blog_id', 'language_code')
    
    def __str__(self):
        return self.name

I want to show the list of blogs those have english translation, with name in english.
How do I need to write my query to get this data:

[
    {
        "name": "1st Blog name in english",
        "content": "content in english",
        "pub_date": "XXX"
    },
    {
        "name": "2nd Blog name in english",
        "content": "content in english",
        "pub_date": "XXX"
    },
]

I use Django 4 with Django Rest Framework. I want my query to start from Blog model.

This is my best try, which doesn’t give me the result I want:

Blog.objects.filter(translations__id = 2)
Asked By: Ulvi

||

Answers:

You can use values() so:

BlogTranslation.objects.filter(language_code__code='en').values('name', 'content', 'blog_id__pub_date')

Then you only need to serialize it to get the data in JSON format.

Edit

To query from Blog model use Q() objects so:

from django.db.models import Q

blogs = Blog.objects.filter(
    translations__language_code__code='en'
).values(
    'translations__name',
    'translations__content',
    'pub_date'
).distinct()
Answered By: Sunderam Dubey

I continued my research and found the answer that outputs the exact JSON I want and it uses the most efficient SQL among other solutions I tried. Thanks Sunderam for your answer. It helped me to continue my research.

This the SQL it executes:

SELECT "blog_blog"."pub_date", 
"blog_blogtranslation"."name" AS "name", 
"blog_blogtranslation"."content" AS "content" 
    FROM "blog_blog" 
INNER JOIN "blog_blogtranslation" ON ("blog_blog"."id" = "blog_blogtranslation"."blog_id_id") 
    WHERE "blog_blogtranslation"."language_code_id" = 2

This is the Django query:

from django.db.models import Prefetch, F

Blog.objects.filter(translations__language_code=2).prefetch_related(
        Prefetch('translations', queryset=BlogTranslation.objects.filter(language_code=2))
    ).values('pub_date').annotate(name=F('translations__name')).annotate(content=F('translations__content'))
Answered By: Ulvi