django查询中逻辑解析器的实现
这将是一个“漫长的过程”。我包括尽可能多的代码和解释。。。如果必要的话,我不会放弃代码 我试图在django查询系统中实现一个逻辑解析器。其中,用户可以针对应用于样本的标记提供复杂查询。这本质上是科学样本库的一部分,用户可以在其中应用定义的标签(组织类型、研究的疾病等)。然后,他们可以创建由这些标记上的逻辑查询定义的样本的持久“篮子”django查询中逻辑解析器的实现,django,django-queryset,logical-operators,Django,Django Queryset,Logical Operators,这将是一个“漫长的过程”。我包括尽可能多的代码和解释。。。如果必要的话,我不会放弃代码 我试图在django查询系统中实现一个逻辑解析器。其中,用户可以针对应用于样本的标记提供复杂查询。这本质上是科学样本库的一部分,用户可以在其中应用定义的标签(组织类型、研究的疾病等)。然后,他们可以创建由这些标记上的逻辑查询定义的样本的持久“篮子” #models.py class Sample(models.Model): name = models.CharField(max_length =
#models.py
class Sample(models.Model):
name = models.CharField(max_length = 255)
class Tag(models.Model):
name = models.CharField(max_length = 255)
samples = models.ManyToManyField(Sample)
A quick example:
#example data:
Sample1 has TagA, TagB, TagC
Sample2 has TagB, TagC, TagD
Sample3 has TagA, TagC, TagD
Sample4 has TagB
#example query:
'TagB AND TagC AND NOT TagD'
将返回样本1。我使用疯狂的字符串求值技巧创建了一组Q()
对象:
def MakeQObject(expression):
"""
Takes an expression and uses a crazy string-eval hack to make the qobjects.
"""
log_set = {'AND':'&','OR':'|','NOT':'~'}
exp_f = []
parts = expression.split()
#if there is a ) or ( then we can't use this shortcut
if '(' in parts or ')' in parts:
return None
for exp in parts:
if exp in log_set:
exp_f.append(log_set[exp])
else:
exp_f.append("Q(tags__name__iexact = '%s')" % exp)
st = ' '.join(exp_f)
qobj = eval(st)
return qobj
但是,对于任何需要复杂的操作顺序或按()分组的操作,这都会失败。给定相同的示例数据,查询:(TagA或TagB)而不是TagD
应返回Sample1、Sample4,但不返回。我实现了一个“一次一个”函数,它可以获取单个样本对象并执行查询。然而,在我的实际数据库中,我有约40000个样本和约400个标记(每个样本约7个),迭代技术需要约4分钟才能在所有样本上完成。所以我每晚计算篮子,然后白天把它们冷冻起来。我担心,随着我开始策划更多的篮子、样品和标签,这将很难扩展
有什么建议吗?首先,为了提高性能,在标记名字段上添加索引可能会有所帮助,因为您正在使用它进行查询。因此,在列中添加db_index=True:
class Tag(models.Model):
name = models.CharField(max_length = 255, db_index=True)
samples = models.ManyToManyField(Sample)
其次,对于解析用户查询,我建议使用几种优秀的基于Python的解析器之一,例如或。这些一开始可能看起来很吓人,但实际上并没有那么难,特别是对于像你这样的简单语法
如果这些对您来说太多了,那么请尝试使用Fredrik的指南滚动您自己的查询。我也尝试过将
()
类型查询“分解”为更长但等效的版本,但没有paren,但也无法使其工作。另外注意:您需要重置数据库,以便syncdb可以看到db_索引。如果无法重置,则需要手动将索引添加到数据库中或使用迁移工具(如South())。。。我想我可以用他们的例子来表示简单的数学表达式“”。只需将math.operations
替换为queryset操作,然后让它处理嵌套等。