Django: отфильтруйте RawQuerySet

у меня есть какой-то странный запрос , поэтому мне нужно выполнить необработанный SQL. Дело в том, что этот запрос становится все больше и больше и с множеством дополнительных фильтров (порядок, критерии столбцов и т. Д.).

Итак, учитывая этот запрос:

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

Это примерно код Python:

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))

Это отлично работает, но мне нужно добавить больше фильтров и упорядочения, например, предположим, мне нужно фильтровать по цвету и упорядочивать по цена, она начинает расти:

#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))

Мне не нравится, как она начала расти, я знаю, что Model.objects.raw () возвращает RawQuerySet, поэтому я хотел бы что-то сделать вот так:

queryset = get_cameras( ... )
queryset.filter(...)
queryset.order_by(...)

Но это не работает. Конечно, я мог бы просто выполнить необработанный запрос и после этого получить фактический QuerySet с данными, но я выполню два запроса. Например:

raw_query_set = get_cameras( ... )
camera.objects.filter(id__in(raw_query_set.ids)) #don't know if it works, but you get the idea

Я думаю, что что-то с QuerySet init или кеш может помочь, но не смог этого сделать.

9
задан Community 23 May 2017 в 12:09
поделиться