2012-04-21 1 views
4

저는 장고 프로젝트를위한 작은 검색 시스템을 구축하고 있습니다 (예, 이미이 제품을 사용하고있는 제품이 많이 있습니다 만, 실제로 사용해 보려합니다.) . "내가 장고 질문이 안녕 StackOverflow에" 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() 

그래서 예를 들어, 내가 텍스트와 객체 페이지 (검색 가능한 서브 클래스)를 만들 : 나는 기본적으로 다음과 같은 모델을 가지고있다. 시스템은이 문장의 각 단어에 대해 Word 인스턴스를 만들고 각 단어가 텍스트에 한 번 나타나는 것을 나타내는 각 WordCount 인스턴스를 만듭니다. 더 많은 단어가 잘 작동 하나를 포함하는 모든 검색 가능한 인스턴스를 얻기 위해 쿼리를 만들기

(단어를 추출 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

감사를보십시오 : 것은이 혼란 조금 점이다 (안 솔루션, 장고 : D) . Sum ('wordcount__count')은 모든 WordCount 객체의 합계를 이전에 필터링 된 인스턴스가 아닌 인스턴스와 관련시킬 것이라고 생각했습니다. 생성 된 SQL 요청을 볼 때 의미가 있다고 생각합니다. – Vincent

+0

@Vincent 예,'print queryset.query'에 의해 생성 된 SQL을 확인할 수 있습니다. – okm

+0

그러나 동일한 결과를 가진 여러 행을 보여줍니다. 별개의 것을 기리는 것은 아닙니다. –