Django: выбор столбцов в разных приложениях с одним и тем же внешним ключом

Это последующий вопрос из этого.

У меня app1/models.py:

class A(models.Model):
    id = models.IntegerField(primary_key=True)
    text = models.CharField(max_length=20)

class B(models.Model):
    fid = models.ForeignKey(A, models.CASCADE)
    text = models.CharField(max_length=20)

class C(models.Model):
    fid = models.ForeignKey(A, models.CASCADE)
    text = models.CharField(max_length=20)

и app2/models.py:

from app1.models import A

class D(models.Model):
    fid = models.ForeignKey(A, models.CASCADE)
    text = models.CharField(max_length=20)

Я хочу получить A.text B.text C.text D.text где A.id == B.fid == C.fid == D.fid == 1. Из приведенного вопроса я смог получить первые 3 столбца, используя:

B.objects.filter(fid=1).values('text', 'fid__text', 'fid__c__text') # B.text, A.text, C.text

Однако я не могу получить D.text с помощью этого запроса. Я знаю, что могу сделать фильтр на D и вычислить его вручную, но я надеюсь на более Djangoic способ.

(В случае многократного совпадения, просуммируйте строки, таким образом, если в B есть 2 строки, которые соответствуют данному fid и 3, 4 для C, D, всего будет возвращено 24 строки)

Попробовать запрос из A модели

A.objects.filter(id=1).values('text', 'b__text', 'c__text', 'd__text')

Я не знаю, почему это не работает. Может быть, это ошибка базы данных? В этом случае Django может быть не при чем. Работает ли это, если заменить fid__c__text на fid__d__text?

Я бы инстинктивно запросил экземпляр модели A, который является "родителем" остальных. Получив экземпляр a, он предлагает b_set.all(), c_set.all() и d_set.all(). Для эффективности работы БД вы можете предварительно получить все связанные объекты с помощью

a = A.objects.prefetch_related('b', 'c', 'd').get( pk=b.fid_id ) 

(Обратите внимание, что при предварительной выборке фильтрация осуществляется путем итерации по a.b_set.all(), а не путем применения .filter(criteria), который снова попадет в БД независимо от предварительной выборки).

Вернуться на верх