2008-11-23 6 views
11

내 구체적인 경우에는 두 가지 종류의 "메시지"가 있습니다. 다시 검색하고 페이지 매김해야합니다. django 사용 어떻게 분리 된 모델의 두 개의 쿼리를 하나의 쿼리로 결합 할 수 있습니까?

의이 세부 사항을 생략하자, 단지 제 1 종은 MSG2

이 두 모델의 필드를 Msg1을라는 모델이고 다른 하나가 호출되는 것을 말하는 공통되는 완전히 다른, 유일한 필드는 두 모델은 "날짜"와 "제목"(물론 ID)입니다.

나는 Msg1.objects.all()Msg2.objects.all()을 얻을 수 있지만이 두 쿼리를 하나의 쿼리로 결합하여 날짜순으로 정렬하고 페이지 매김 할 수 있습니까?

쿼리의 지연 성을 유지해야합니다.

평범한 해결책은 list(query)입니다. 둘 다 쿼리하여 파이썬 목록에 결합하십시오. 그러나 이는 분명한 이유로 비효율적입니다.

모델 및 dp-api에서 django 참조를 살펴 보았지만 다른 모델/테이블의 쿼리를 하나로 결합하는 방법은없는 것으로 보입니다.

+0

"비효율적 인 이유는 분명합니다." 측정 항목이 있습니까? 비효율적 인 이유가 분명하지 않기 때문에 묻습니다. –

+0

일단 내가 (쿼리)를 나열하면 모든 결과가 나오고 가능한 한 늦게 나가기를 원하기 때문에 생각합니다. –

+0

은 페이지 당 20 개 정도만 표시하면서 모든 항목 (1000 일 수 있음)에 대한 데이터베이스를 조회하므로 비효율적입니다. – hasen

답변

11

난 당신이 Model inheritance를 사용하는 것이 좋습니다 것입니다.

날짜와 제목이 포함 된 기본 모델을 만듭니다. 설명한대로 Msg1 및 Msg2를 서브 클래 싱하십시오. 기본 모델을 사용하여 모든 쿼리를 수행하고 (페이지를 채우기 위해) 마지막 순간에 파생 유형으로 전환하십시오.

상속에 대한 정말 좋은 점은 django가 다른 모델의 외래 키에서 기본 모델을 사용할 수있게하여 전체 애플리케이션의 유연성을 높일 수 있다는 것입니다. 후드 아래에는 일대일 키가 포함 된 하위 모델 당 테이블이있는 기본 모델의 테이블 일뿐입니다.

+1

내 기본 클래스가 추상 클래스 인 경우 어떻게해야합니까? 몇 가지 코드 예제를 보여줄 수 있습니까? –

2

"이 두 쿼리를 하나의 쿼리로 결합하여 날짜순으로 정렬하고 페이지 매김을 하시겠습니까?"

  1. 이것이 바로 SQL 조합입니다. Django ORM을 닫고 SQL 유니온을 사용하십시오. SQL은 일시적인 결과를 만들어야하기 때문에 훌륭하게 빠르지는 않습니다.

  2. 정렬 할 수있는 임시 결과를 만듭니다. 목록에는 정렬 방법이 있으므로 두 결과를 하나의 목록으로 병합해야합니다.

  3. 결과를 페이지 매김하는 두 개의 쿼리 집합을 허용하는 병합 알고리즘을 작성합니다.


편집. 다음은 병합 알고리즘입니다.

def merge(qs1, qs2): 
    iqs1= iter(qs1) 
    iqs2= iter(qs2) 
    k1= iqs1.next() 
    k2= iqs2.next() 
    k1_data, k2_data = True, True 
    while k1_data or k2_data: 
     if not k2_data: 
      yield k1 
      try: 
       k1= iqs1.next() 
      except StopIteration: 
       k1_data= False 
     elif not k1_data: 
      yield k2 
      try: 
       k2= iqs2.next() 
      except StopIteration: 
       k2_data= False 
     elif k1.key <= k2.key: 
      yield k1 
      try: 
       k1= iqs1.next() 
      except StopIteration: 
       k1_data= False 
     elif k2.key < k1.key: # or define __cmp__. 
      yield k2 
      try: 
       k2= iqs2.next() 
      except StopIteration: 
       k2_data= False 
     else: 
      raise Exception("Wow...") 

당신은 페이지 매김에 접을 수

def paginate(qs1, qs2, start=0, size=20): 
    count= 0 
    for row in merge(qs1, qs2): 
     if start <= count < start+size: 
      yield row 
     count += 1 
     if count == start+size: 
      break 
+0

이 경로를 따르려면 SQL에서 정렬을 수행해야합니다 (SQL에서 정렬을 가속화하기 위해 인덱스를 사용할 수 있기 때문에). 정렬 전에 중간 정렬 결과를 제한하여 크기를 줄일 수 있기를 바랍니다 임시 데이터의 –

+0

그러나 Union은 테이블, 계산, 리터럴 등의 * 조합 일 수 있기 때문에 공용체는 중간 결과를 만들고 정렬해야합니다. 어쩌면 당신은 최적화 할 수 있지만 일반 버전 *은 작동해야합니다. –

관련 문제