.extra в django (где = пункты перекрываются переименованием таблицы .filter (foo__in = ... subselects) - PullRequest
3 голосов
/ 21 июля 2010

Короче говоря, имена таблиц всех запросов, которые находятся внутри фильтра, переименовываются в u0, u1, ..., так что мои дополнительные предложения where не будут знать, на какую таблицу указывать.Я бы не хотел делать вручную все запросы для каждого способа, которым я мог бы отобрать эти данные, и мой текущий обходной путь состоит в том, чтобы превратить мои дополнительные запросы в pk values_lists, но это действительно медленно и что-то вроде мерзости.

Вот как все это выглядит.В большинстве случаев вы можете игнорировать детали того, что происходит в дополнительном методе менеджера, за исключением первой строки sql, которая указывает на products_product.id:

def by_status(self, *statii):
    return self.extra(where=["""products_product.id IN                                                                                                                                                  
        (SELECT recent.product_id                                                                                                                                                                          
          FROM (                                                                                                                                                                                           
            SELECT product_id, MAX(start_date) AS latest                                                                                                                                                   
            FROM products_productstatus                                                                                                                                                                    
            GROUP BY product_id                                                                                                                                                                            
          ) AS recent                                                                                                                                                                                      
          JOIN products_productstatus AS ps ON ps.product_id = recent.product_id                                                                                                                           
          WHERE ps.start_date = recent.latest                                                                                                                                                              
            AND ps.status IN (%s))""" % (', '.join([str(stat) for stat in statii]),)])

, которая прекрасно работает во всех ситуациях, связанных только с таблицей products_product..

Когда я хочу получить эти продукты в качестве подвыбора, я делаю:

Piece.objects.filter(
    product__in=Product.objects.filter(
        pk__in=list(
            Product.objects.by_status(FEATURED).values_list('id', flat=True))))

Как я могу сохранить обобщенные возможности набора запросов, но все еще использовать дополнительное условие where?

1 Ответ

3 голосов
/ 21 июля 2010

Сначала: проблема не совсем ясна для меня. Является ли второй блок кода в вашем вопросе фактическим кодом, который вы хотите выполнить? В этом случае запрос должен работать так, как ожидалось, так как подвыбор не выполняется.

Я предполагаю, что вы хотите использовать второй блок кода без list() вокруг подвыбора, чтобы предотвратить выполнение второго запроса.


Документация django относится к этой проблеме в документации о дополнительном методе . Однако эту проблему нелегко преодолеть.

Самое простое, но наиболее "хакское" решение - наблюдать, какой псевдоним таблицы создается django для таблицы, которую вы хотите запросить в дополнительном методе. Вы можете рассчитывать на постоянное именование этого псевдонима, если вы строите запрос всегда одинаково (вы не меняете порядок нескольких методов extra или filter вызовов, вызывающих соединение).

Вы можете проверить запрос, который будет выполнен в наборе запросов БД, используя:

print Model.objects.filter(...).query

Это покажет псевдонимы, которые используются для таблиц, которые вы хотите запросить.

...