warpedspeed warpedspeed - 8 days ago 4
Python Question

Django ORM compound filter with variables

I'm by no means a Django expert, and need some guidance on a problem.

For background, I have a older .NET project that I've been tasked to turn into Django project. The project gets a full list of objects and then runs a large set of user set filters to end up with the desired set of objects.

One of the filters in .NET might be like so ...

matched.RemoveAll(x => ((x.annualIncome / 12) - x.payment) < monthlyIncome);


I'm trying to figure out how I would do this with the django ORM. I'm kind off stuck on this.

In a pseudo-code django ORM version (yes, this will not work):

matched.exclude(((annualIncome /12)-payment)__gt = monthlyIncome)


There are 30+ filters before this one so I can't re-do them all in a different manner. I can obviously go through each object and filter but I decided to ask first.

I'm open to solutions here or friendly "RTFM, this pages answers it."

Thanks in advance, and mods please edit with a better title as my brain is now officially fried from 3 days coding with the Flu.

Answer

In that case welcome to the magical world of Django ORM (and not in a bad sense, it's actually pretty reasonable most of the time :).

from django.db.models import F, Case

# Your stuff
matches.annotate(
    req=Case(default=(F('annualIncome') / 12) - F('payment'))
).exclude(req__gt=monthlyIncome)

Because you can't query directly in that kind of a calculation, then the F object tells ORM that this should come from the database, go and get it.
Untested (due to lack of similar case in my projects), but if problems arise, do let me know.

PS. You can change the req name to whatever you like.

EDIT:
Wow, this is awkward. You can just do it without the Case as well.

matches.annotate(req=(F('annualIncome') / 12) - F('payment')).exclude(req__gt=monthlyIncome)