我不确定这是一个问题还是对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
函数。
如果我不删除该列,则在解析器满足“与”或“或”运算时,就会出现错误django.db.utils.OperationalError: SELECTs to the left and right of INTERSECT do not have the same number of result columns
。
从2012年到今年年初,我一直在使用SQLAlchemy,在那里我已经实现了与此非常相似的东西。使用Django,给人的印象是我在一个过于智能的抽象层后面。