これは「長いもの」になります。できるだけ多くのコードと説明を含めています...必要に応じてコードを捨てることはありません。
django クエリ システムに論理パーサーを実装しようとしています。サンプルに適用されるタグに対してユーザーが複雑なクエリを提供できる場所。これは本質的に、ユーザーが定義されたタグ (組織タイプ、研究された疾患など) を適用できる科学サンプル リポジトリの一部です。次に、これらのタグに対する論理クエリによって定義されたサンプルの永続的な「バスケット」を作成できます。
#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'
Sample1 を返します。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 OR TagB) AND NOT TagD
Sample1、Sample4 が返されるはずですが、返されません。単一の Sample オブジェクトを取得してクエリを実行できる「1 つずつ」関数を実装しました。ただし、私の実際のデータベースには、最大 40,000 個のサンプルと最大 400 個のタグ (サンプルあたり約 7 個) があり、すべてのサンプルで反復手法を完了するのに最大 4 分かかります。だから私は毎晩バスケットを計算し、日中はそれらを凍結します. より多くのバスケット、サンプル、およびタグをキュレートし始めると、これが不十分になるのではないかと心配しています.
助言がありますか?