Я не уверен, является ли это вопросом, запросом функции к 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, у меня создается впечатление, что я нахожусь за слишком умным уровнем абстракции.