I have some kind of weird query , so I have to execute raw SQL. The fact is that this query is becoming more and more with many additional filters (ordering, column criteria, etc.).
So, given this request:
SELECT DISTINCT Camera.* FROM Camera c INNER JOIN cameras_features fc1 ON c.id = fc1.camera_id AND fc1.feature_id = 1 INNER JOIN cameras_features fc2 ON c.id = fc2.camera_id AND fc2.feature_id = 2
This is roughly Python code:
def get_cameras(features): query = "SELECT DISTINCT Camera.* FROM Camera c" i = 1 for f in features: alias_name = "fc%s" % i query += "INNER JOIN cameras_features %s ON c.id = %s.camera_id AND %s.feature_id = " % (alias_name,alias_name,alias_name) query += " %s " i += 1 return Camera.objects.raw(query, tuple(features))
This works fine, but I need to add more filters and arrange, for example, suppose I need to filter by color and by price by price, it starts to grow:
#extra_filters is a list of tuples like: # [('price', '=', '12'), ('color' = 'blue'), ('brand', 'like', 'lum%'] def get_cameras_big(features,extra_filters=None,order=None): query = "SELECT DISTINCT Camera.* FROM Camera c" i = 1 for f in features: alias_name = "fc%s" % i query += "INNER JOIN cameras_features %s ON c.id = %s.camera_id AND %s.feature_id = " % (alias_name,alias_name,alias_name) query += " %s " i += 1 if extra_filters: query += " WHERE " for ef in extra_filters: query += "%s %s %s" % ef #not very safe, refactoring needed if order: query += "order by %s" % order return Camera.objects.raw(query, tuple(features))
So, I donβt like how it started to grow, I know that Model.objects.raw() returns a RawQuerySet, so I would like to do something like this:
queryset = get_cameras( ... ) queryset.filter(...) queryset.order_by(...)
But that does not work. Of course, I could just execute the raw query and after that get the actual QuerySet with the data, but I will execute two queries. How:
raw_query_set = get_cameras( ... ) camera.objects.filter(id__in(raw_query_set.ids))
I think something with a QuerySet init or cache might do the trick, but couldn't do it.