Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django prefetch through table

Tags:

python

django

I have a Django model which has a manyToMany relation with an additional column:

class Field(models.Model):
    table = models.ForeignKey(
        Table, on_delete=models.CASCADE,
        verbose_name=_(
            u"Table"), related_name="fields"
    )
    supportedLanguages = models.ManyToManyField(
        Language,
        through='FieldsLanguages',
        ('field', 'language'),
        verbose_name=_(
            u"Supportedlanguage"),
        help_text=_(
            u"The language that the field supports (must be a language supported by the table.")
    )

Here is my through table:

class FieldsLanguages(models.Model):
    field = models.ForeignKey(Field, on_delete=models.CASCADE)
    language = models.ForeignKey(Language, on_delete=models.CASCADE)
    defaultValue = models.CharField(
        max_length=255, blank=True, null=True, verbose_name=_(u"Default value"),
        help_text=_(
            u"The default value of this field in this language (Overrides the default value of the field).")
    )

I would like to retrieve each defaultValue from the through table and its language in one query.

I thought this would do the job:

table = Table.objects.get(pk=1)
fields = list(table.fields.prefetch_related("supportedLanguages").all().order_by("position"))

But unfortunately, it doesn't get me the defaultValue of each relation but only its Language. It could be done in the same query as the query goes already through FieldsLanguages to retrieve the Foreign Keys.

How can I accomplish this?

like image 738
hadNoIdea Avatar asked Sep 06 '25 03:09

hadNoIdea


2 Answers

It wasn't really what I was lookig for but it helped me to build my query:

table = Table.objects.get(pk=1)
fields = table.fields.prefetch_related("fieldslanguages_set", "fieldslanguages_set__language").order_by("position")
for field in fields:
    for fl in field.fieldslanguages_set.all():
        print(fl.defaultValue, fl.language)

The problem with Kevin Christopher Henry's answer is that it will query the database for each field in the for-loop. Here it will send only 4 queries.

like image 157
hadNoIdea Avatar answered Sep 07 '25 22:09

hadNoIdea


The through table is a table like any other, which means you can reference it through the related names of its ForeignKeys.

table = Table.objects.get(pk=1)
fields = table.fields.prefetch_related("fieldslanguages__language")
                     .order_by("position"))

for field in fields:
    for fl in field.fieldslanguages_set.all():
        print(fl.default, fl.language)
like image 28
Kevin Christopher Henry Avatar answered Sep 08 '25 00:09

Kevin Christopher Henry