удаление столбца из набора запросов - PullRequest
1 голос
/ 22 мая 2019

Я не уверен, является ли это вопросом, запросом функции к Django, или, может быть, я делаю вещи излишне сложными.Я пишу пользовательский интерфейс, где я позволяю пользователю писать запросы, которые я преобразую в создание, модификацию и комбинацию наборов запросов Django.

программа использует ply, (запись в p[0] суммына return) и здесь у вас есть несколько выдержек из грамматики:

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

def p_field_fieldname(p):
    'field : fieldname'
    p[0] = p[1]

def p_field_dot_fieldname(p):
    'field : field DOT fieldname'
    p[0] = '{}__{}'.format(p[1], p[3])

Реализация теста для включения в список (я использую глобальный search_domain, который, очевидно, вызывает проблемы, но здесь дело не в этом).

def p_bfactor_list_comprehension(p):
    'bfactor : field IN LBRACKET valuelist RBRACKET'
    p[0] = search_domain.objects.filter(**{'{}__in'.format(p[1]): p[4]})

объединение bfactor токены.

def p_bterm_bfactor(p):
    'bterm : bfactor'
    p[0] = p[1]

def p_expression_or_bterm(p):
    'expression : expression OR bterm'
    p[0] = p[1].union(p[3])

def p_bterm_and_bfactor(p):
    'bterm : bterm AND bfactor'
    p[0] = p[1].intersection(p[3])

Пока все хорошо.Проблема, с которой я столкнулся, заключается в том, что когда я вводил агрегатные функции в сочетании с другими запросами, позволяя пользователю писать такие вещи, как:

taxon where rank.id>=17 and count(verifications)=0

Я реализую count,Я сделал это, добавив дополнительный столбец и протестировав его, но потом мне было трудно пытаться пересечь два набора запросов, результаты двух предложений count(verifications)=0 и rank.id>=17.

Я попытался defer, но мне не удалось удалить столбец после того, как был использован.

В конце я написал это ужасно уродливое решение,

def p_bfactor_aggregate_comparison(p):
    'bfactor : aggregate LPAREN field RPAREN operator value'
    from django.db.models import Count, Sum  # adding field to qs
    _, aggregate, _, field, _, operator, value = p
    f = {'count': Count, 'sum': Sum}[aggregate]
    q = search_domain.objects.annotate(temp_field=f(field))
    matching = set(i['id'] 
        for i in q.filter(**{'temp_field__{}'.format(operator): value})
                  .values('id'))
    p[0] = search_domain.objects.filter(id__in=matching)

мое другое лучшее предположение (точнее, я надеюсь, что это сработает) было:

def p_bfactor_aggregate_comparison(p):
    'bfactor : aggregate LPAREN field RPAREN operator value'
    from django.db.models import Count, Sum  # adding field to qs
    _, aggregate, _, field, _, operator, value = p
    f = {'count': Count, 'sum': Sum}[aggregate]
    q = search_domain.objects.annotate(temp_field=f(field))
    p[0] = q.filter(**{'temp_field__{}'.format(operator): value}
        ).WHATEVERWORKS('temp_field')

к сожалению, однако, я не нашел функцию WHATEVERWORKS.

, если я не сделаюудалите этот столбец, как только синтаксический анализатор встретит продукцию AND или OR, он выдаст ошибку django.db.utils.OperationalError: SELECTs to the left and right of INTERSECT do not have the same number of result columns.

с 2012 до начала этого года, я использую SQLAlchemy, где я уже реализовал что-то оченьпохоже на это.используя Django, у меня создается впечатление, что я нахожусь за слишком умным уровнем абстракции.

...