Hello!
For instance, I have two models (simplified):
class User(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Order(models.Model):
amount = models.DecimalField(max_digits=19, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name="orders")
How I can make separated subqueries (with own grouping, ordering, filtering) by QuerySet API in T-SQL way?
SELECT
u.id,
u.first_name,
u.last_name,
sq1.min_amount,
sq1.max_amount
FROM
[User] u
-- Subquery #1
LEFT OUTER JOIN (
SELECT
[user_id],
MIN(amount) min_amount,
MAX(amount) max_amount
FROM
[Order]
GROUP BY
[user_id]
) sq1 ON u.id = sq1.[user_id]
-- Subquery #2
-- LEFT OUTER JOIN (...) sq2
-- Subquery #3
-- OUTER APPLY (...) sq3
If I use .annotate(), I don’t get desirable SQL result because grouping runs in main query, not in subquery:
User.objects.values(
'id',
'first_name',
'last_name',
).annotate(
min_amount=Min('orders__amount'),
max_amount=Max('orders__amount')
)
If I use Subquery() in .annotate(), subquery runs in SELECT area and it’s not good for the performance, because if I need several fields from one subquery (min_amount and max_amount), sql server runs two queries instead of one.
Is there any solution?
May be I can use .prefetch_related() somehow as a substitution of subquery in T-SQL for each query
Prefetch(
'orders',
queryset=Order.objects. #staff with .values(), annotate(Min(), Max()) and etc.
to_attr='sq1'
)
and then I could use fields from ‘sq1’ in main query User.objects…?