It seems that Django developers are aware about the fact that there's no way to filter on calculated fields like this in MySQL:
SomeModel.objects.extra(select={ 'total': 'SOME CALCULATION GOES HERE' }, where=['total < 10'])
OR
SomeModel.objects.extra(select={ 'total': 'SOME CALCULATION GOES HERE' }).filter(total__lt=10)
This was described in https://code.djangoproject.com/ticket/8784 but unfortunately it looks like it will take another year to implement with current speed. I understand the concern of development team that ideally they want to get rid of the .extra() because by writing pure SQL in that statement code becomes non DB-agnostic. I believe that dealing with calculated field is fairly common task in many projects and I currently faced the problem that I can't solve: I think the majority of community often uses this dirty workaround:
SomeModel.objects.extra(select={ 'total': 'SOME CALCULATION GOES HERE' }, where=['1 HAVING total < 10'])
and in fact it works, but only till the moment when you need to add filter on the result of the statement above:
SomeModel.objects.extra(select={ 'total': 'SOME CALCULATION GOES HERE' }, where=['1 HAVING total < 10']).filter(id__gt=300)
this doesn't work anymore, because it translates to the wrong SQL statement:
SELECT id, ..., (SOME CALCULATION) AS total
FROM some_table
WHERE (1 AND HAVING total < 10 AND id > 300)
What I want to achieve is to have some kind of restriction in custom model manager which would allow me to write code like this:
class SomeModelManager(models.Manager):
def apply_total_restriction(self, restriction_num):
return self.extra(select={ 'total': 'CALCULATION GOES HERE' }).filter(total__lt=restriction_num)
...
SomeModel.objects.apply_total_restriction(restriction_num).filter(created_by_id__exact=1)
Question is: does anybody know how to overcome this temporary (hopefully) restriction and to fulfill the task? Any possible alternatives?