2012-04-21 17 views
4

私はDjangoプロジェクトのための小さな検索システムを構築しています(私は知っています、これをやっている製品はたくさんありますが、 。私は基本的に次のモデルいる :Django - 中間テーブルを使用してManyToManyフィールドに注釈を付ける

class Word(models.Model): 
    """ A searchable word. 
    We only store the slugified value 
    """ 
    slug = models.SlugField(unique = True) 

class Searchable(models.Model): 
    """ Superclass for Searchable objects. 
    """ 
    words = models.ManyToManyField(
     Word, 
     through='WordCount') 

class WordCount(models.Model): 
    """ Occurences of a word in a Searchable object. 
    """ 
    word = models.ForeignKey(Word) 
    item = models.ForeignKey(Searchable) 
    count = models.IntegerField() 

だから例えば、私はテキストと(サーチャブルをサブクラス)オブジェクトのページを作成する「ハローStackOverflowの私は、Djangoの質問があります」。システムは、この文の各単語、および各単語がテキストに一度現れることを示す各WordCountインスタンスのWordインスタンスを作成します。

より多くの単語が正常に動作1を含むすべての検索可能なインスタンス(単語を抽出し、そこからリストを作るsearchable_text)を取得するクエリの作成:

def search(query) 
    tokens = searchable_text(query) 
    words = Word.objects.filter(
         reduce(operator.or_, 
           [models.Q(slug__contains = t) 
           for t in tokens])) 

    return Searchable.objects.filter(words__in = words) 

は、今私がやりたいものを使用することです中間結果を順序付けるための関係。私は、次のコードは動作しませんので、クエリセットを維持したいが、私は(注釈を作るために醜いパッチ適用で)何をしたいかのアイデアを提供したい:

したがって、基本的
def search(query) 
    tokens = searchable_text(query) 
    words = Word.objects.filter(
         reduce(operator.or_, 
           [models.Q(slug__contains = t) 
           for t in tokens])) 
    results = [] 
    for obj in Searchable.objects.filter(words__in = words): 
     matching_words = obj.wordcount_set.filter(word__in = words) 
     obj.weight = sum([w.count for w in matching_words]) 
     results.append(obj) 

    return sorted(results, 
        reverse = True, 
        key = lambda x: x.weight) 

: - 私はすべてを取得しますクエリに含まれているWordオブジェクト(または部分的に一致する "Stack"を検索した場合、Word "StackOverflow"が考慮されます) - これらの単語のいずれかとの関係を持つすべてのオブジェクトを取得します - 各オブジェクト、以前に計算されたWordのリストにあるWordに関連するすべての関連するWordCountオブジェクトを選択してから、 'count'属性の合計を計算して注釈 'weight'として保存します - '

これはQuerySetで実行可能かどうかわかりませんが、後でいくつかの結果をフィルタリングするなど、いくつかの余分なアクションのフォーマットを保持したいと思います。

私は改善がたくさんあることを知っていますが、それは良いスタートになるでしょう。答えを

おかげで、 ヴィンセント

答えて

2

、それは魔法のように動作

Searchable.objects.filter(words__in=words).annotate(
    weight=models.Sum('wordcount__count')).order_by('-weight') 
+0

感謝を試してみてください:) ことは、それが混乱のビットがあるということです(ないあなたのソリューションでは、Django自体:D) 。 Sum( 'wordcount__count')は、以前にフィルタリングされたものではなく、インスタンスに関連するすべてのWordCountオブジェクトの合計を作成すると考えました。 生成されたSQLリクエストを見ると意味があると思います。 – Vincent

+0

@Vincentはい、 'print queryset.query'によって生成されたSQLをチェックできます – okm

+0

しかし、同じ結果を持つ複数の行が表示されています。それは別個のものを称えるものではありません。 –

関連する問題