Reputation: 65
I have following models:
class Domain(models.Model):
name = models.CharField(...)
plan = models.ForeignKey(Plan, ....)
class Plan(models.Model):
name = models.CharField(...)
num_ex_accounts = models.IntegerField(...)
class PlanDetails(models.Model):
accounts = models.IntegerField()
plan = models.ForeignKey(Plan, ....)
class Mailbox(models.Model):
domain = models.ForeignKey(Domain, ...)
Any domain has a plan, any plan has N plan details which has accounts value for create mailboxes using a domain, I want to get in a queryset domains which exceed the accounts value, using raw sql the sql is like:
SELECT domain
FROM domain, plan
WHERE plan.id = domain.plan_id
AND (
SELECT SUM(accounts)
FROM plandetails WHERE plandetails.plan_id=plan.id
)
<=
(
SELECT COUNT(*)
FROM mailbox WHERE mailbox.domain_id=domain.id
)
I tried in django something like this:
domains = Domain.objects.filter(
Q(
PlainDetails.objects.filter(plan = Domain.plan).aggregate(Sum('accounts')) <=
Mailbox.objects.filter(domain = Domain).count()
)
)
But it doesn't works, it throws an error about the Domain.plan, is there a way to reference that field value from parent query in the sub-query? is this queryset valid or is there another (better) approach? or I should use simply raw sql, what is the best option in this case?
Upvotes: 0
Views: 2365
Reputation: 1497
If you are using Django 1.8 and higher, then try this:
Domain.objects.annotate(
account_sum=Sum('plan__plandetails_set__accounts'),
mailbox_count=Count('mailbox_set__id'))
).filter(
account_sum__lte=F('mailbox_count')
)
Replace plandetails_set
and mailbox_set
with the appropriate related name
if you explicitly specified any in the ForeignKey
fields to Plan
. Those two are just the defaults if none has been specified.
UPDATE For very complex queries, it might be better to just run the actual SQL using cursors. Django ORM is usually good enough, but depending on the needs, it may not be enough. Please view the docs.
Upvotes: 2