This is a follow-up question of this.
I have 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)
and app2/models.py
:
from app1.models import A
class D(models.Model):
fid = models.ForeignKey(A, models.CASCADE)
text = models.CharField(max_length=20)
I wish to get A.text
B.text
C.text
D.text
where A.id == B.fid == C.fid == D.fid == 1
. From the referred question, I was able to retrieve the first 3 columns using:
B.objects.filter(fid=1).values('text', 'fid__text', 'fid__c__text') # B.text, A.text, C.text
However I cannot get D.text
using this query. I know I can do a filter on D
and give it a manual calculation, but I'm looking forward to a more Djangoic way.
(In case of a multi-match, product the rows, so if there are 2 rows in B
that matches the given fid
and 3, 4 for C
, D
, a total of 24 rows in returned.)
For future visitors: both weAreStarsDust's and nigel222's answer are great and worth reading.
CodePudding user response:
I don't know why it doesn't work. Is it a database error? In which case it may be nothing to do with Django. Does it work if you replace fid__c__text
with fid__d__text
?
I would instinctively query on the A
model instance, which is the 'parent' of the others. Having obtained the instance a
, it offers b_set.all()
, c_set.all()
, and d_set.all()
. For DB efficiency you can prefetch all the related objects with
a = A.objects.prefetch_related('b', 'c', 'd').get( pk=b.fid_id )
(Note, having prefetched, filter by iterating through a.b_set.all()
not by applying a .filter(criteria)
which will hit the DB again regardless of the prefetch).
CodePudding user response:
Try query from A
model
A.objects.filter(id=1).values('text', 'b__text', 'c__text', 'd__text')
or
A.objects.filter(id=1).values('text', 'b_set__text', 'c_set__text', 'd_set__text')
More details about _set
can be found in the RelatedManager docs