문제

다음 모델 구조가 있습니다.

class Container(models.Model):
    pass

class Generic(models.Model):
    name = models.CharacterField(unique=True)
    cont = models.ManyToManyField(Container, null=True)
    # It is possible to have a Generic object not associated with any container, 
    # thats why null=True

class Specific1(Generic):
    ...

class Specific2(Generic):
    ...

...

class SpecificN(Generic):
    ...

모든 것을 검색해야합니다 Specific-특정 컨테이너와 관계가있는 유형 모델.

그것에 대한 SQL은 다소 사소하지만 그것은 문제가 아닙니다. 불행히도, 나는 Orms (특히 Django 's ORM)와 함께 일한 경험이 없었으므로 여기서 패턴이 누락 될 수 있습니다.

무차별적인 방식으로 완료되면 -

c = Container.objects.get(name='somename') # this gets me the container
items = c.generic_set.all() 
# this gets me all Generic objects, that are related to the container
# Now what? I need to get to the actual Specific objects, so I need to somehow
# get the type of the underlying Specific object and get it
for item in items:
    spec = getattr(item, item.get_my_specific_type())

이로 인해 수많은 DB 히트 (컨테이너와 관련된 각 일반 레코드마다 하나씩)가 발생하므로이를 수행하는 방법은 아닙니다. 이제는 특정 객체를 직접 가져 와서 수행 할 수 있습니다.

s = Specific1.objects.filter(cont__name='somename')
# This gets me all Specific1 objects for the specified container
...
# do it for every Specific type

그렇게하면 각 특정 유형에 대해 DB가 한 번에 맞습니다 (허용 가능).

.select_related ()는 m2m 관계에서 작동하지 않으므로 여기서는 큰 도움이되지 않습니다.

반복하려면 최종 결과는 특정 옥스 객체 (일반적인 것이 아님)의 모음이어야합니다.

도움이 되었습니까?

해결책

나는 당신이 이미 두 가지 쉬운 가능성을 설명했다고 생각합니다. 일반에 대해 단일 필터 쿼리를 수행 한 다음 각 항목을 특정 하위 유형 (N+1 쿼리, 여기서 N이 반환 된 항목 수)에 캐스트하거나 각 특정 테이블에 대해 별도의 쿼리를 만듭니다 (k에서는 k가 나타납니다. 쿼리, 여기서 k는 특정 유형의 수입니다).

실제로이 중 어느 것이 실제로 더 빠른지 확인하는 것은 벤치마킹의 가치가 있습니다. 두 번째는 쿼리가 적기 때문에 더 좋아 보이지만 각 쿼리는 M2M 중간 테이블과 결합해야합니다. 전자의 경우 하나의 쿼리 만 수행 한 다음 많은 간단한 쿼리 만 수행합니다. 일부 데이터베이스 백엔드는 더 적고 복잡한 쿼리보다 작은 쿼리로 더 잘 수행됩니다.

두 번째가 사용 사례에 대해 실제로 훨씬 빠르고 코드를 정리하기 위해 추가 작업을 수행하려는 경우 모든 것을 "사전 가져 오기"하는 일반 모델에 대한 사용자 정의 관리자 메소드를 작성할 수 있어야합니다. 하위 유형 테이블 당 하나의 쿼리 만 사용하여 주어진 쿼리 세트에 대한 관련 특정 테이블의 하위 유형 데이터; 방법과 비슷합니다 이 스 니펫 대량 프리 페치로 일반적인 외래 키를 최적화합니다. 이렇게하면 첫 번째 옵션의 건조기 구문과 함께 두 번째 옵션과 동일한 쿼리가 제공됩니다.

다른 팁

완전한 대답은 아니지만이 작업을 수행하여 많은 수의 히트를 피할 수 있습니다.

items= list(items)
for item in items:
    spec = getattr(item, item.get_my_specific_type())

대신 :

for item in items:
    spec = getattr(item, item.get_my_specific_type())

실제로, 캐스트를 파이썬 목록으로 강요함으로써 Django ORM이 쿼리 세트의 모든 요소를로드하도록 강요합니다. 그런 다음 한 쿼리로이를 수행합니다.

실수로 다음 게시물에 고정되어 있습니다.

http://lazypython.blogspot.com/2008/11/timeline-view-in-django.html

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top