I have a model A with a ForeignKey to B:
JavaScript
x
3
1
class A(models.Model):
2
b = models.ForeignKey(B, on_delete=models.CASCADE)
3
A ManyToMany relationship with an extra field that weight any B and C relation:
JavaScript
1
5
1
class B2C(models.Model):
2
b = models.ForeignKey(B, on_delete=models.CASCADE)
3
c = models.ForeignKey(C, on_delete=models.CASCADE)
4
weight = models.IntegerField(default=0)
5
And I need to order the A model (A.objects.filter(…)) using the weight of B2C for a given instance of C.
For only one A instance I can do :
JavaScript
1
10
10
1
# Example of C instance
2
c = C.objects.get(pk=1)
3
4
# Single instance of A
5
a = A.objects.get(pk=1)
6
7
# Getting the weight for this instance
8
# A => B => B2C WHERE metier=metier
9
weight = a.b.b2c_set.get(c=c)
10
But I don’t know how to do apply this on a queryset (like using it in a annotate
).
During my research I’ve found theses F()
, ExpressionWrapper
, SubQuery
, annotate
but I can’t figure out how to use them for my problem.
Thanks for reading :)
Advertisement
Answer
As you already notice, you need to use a Subquery
[Django docs] to annotate
the weight. You can use OuterRef
to refer to the outer queries b
while filtering and also use Coalesce
[Django docs] just in case to provide a default value:
JavaScript
1
10
10
1
from django.db.models import OuterRef, Subquery
2
from django.db.models.functions import Coalesce
3
4
5
weight_subquery = B2C.objects.filter(b=OuterRef('b'), c=given_c_instance)
6
7
queryset = A.objects.annotate(
8
weight=Coalesce(Subquery(weight_subquery.values('weight')[:1]), 0)
9
).order_by('weight')
10