장고 앱에 대한 데이터베이스 쿼리를 최적화하려고합니다.django many-to-many 필드 : 프리 페치 기본 키
class Label(models.Model):
name = models.CharField(max_length=200)
# ... many other fields ...
class Thing(models.Model):
name = models.CharField(max_length=200)
labels = models.ManyToManyField(Label)
나는 모든 Label
들과 Thing
의를 가져와 Thing
의 자신의 id
의 (기본 키)를 사용하여 Label
의 참조하는 JSON 데이터 구조로 그들을두고하는 기능을 가지고 : 여기에 간단한 예입니다. 이런 식으로 뭔가 :
{
'labels': [
{ 'id': 123, 'name': 'label foo' },
...
],
'things': [
{ 'id': 45, 'name': 'thing bar', 'labels': [ 123, ... ] },
...
]
}
장고를 사용하여 이러한 데이터 구조를 얻는 가장 효율적인 방법은 무엇입니까? 내가 LLabel
들과 TThing
의이 있다고 가정하고, 평균 Thing
는 XLabel
의가 있습니다.
방법 1 : model_to_dict(thing)
필요가 개별적으로 Thing
의 Label
의를 가져올 수 있기 때문에이
data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in Thing.objects.all()]
이, (1 + 1 + T) 데이터베이스 쿼리를합니다.
방법 2 :이
data = {}
data['labels'] = [model_to_dict(label) for label in Label.objects.all()]
data['things'] = [model_to_dict(thing) for thing in
Thing.objects.prefetch_related('labels').all()]
이 있습니다 (1 + 1 + 1) 데이터베이스 쿼리에만 Thing
의 지금 가져 자신의 Label
의는 하나의 추가 쿼리에서 프리 페치가 있기 때문이다.
이것은 여전히 만족스럽지 않습니다.prefetch_related('labels')
은 id
만 필요하지만 동일한 Label
사본을 여러 개 가져옵니다. Label
의 id
초만 미리 가져올 수 있나요? 내가 시도한 prefetch_related('labels__id')
하지만 그 작동하지 않았다. 또한 이 큽니다 (수백)이기 때문에 prefetch_related('labels')
은 큰 IN
절이있는 SQL 쿼리를 생성합니다. L은 (< 10) 훨씬 작다, 그래서 내가 대신이 작업을 수행 할 수 있습니다 :
방법 3 :
data = {}
data['labels'] = [model_to_dict(label) for label in
Label.objects.prefetch_related('thing_set').all()]
things = list(Thing.objects.all())
# plug in label ids by hand, and also fetch things that have zero labels
# somehow
이 작은 IN
절 결과,하지만 여전히 prefetch_related('thing_set')
페치 때문에 만족하지 않습니다 Thing
에 Label
이 여러 개인 경우 Thing
이 중복됩니다.
요약 :
Label
및 Thing
가 ManyToManyField
의해 접속된다. 어쨌든 모두Label
및 Thing
을 가져오고 있습니다. 그렇다면 어떻게 다 - 대 - 다 관계를 효과적으로 가져올 수 있습니까?
아마도 m2m에 대한 중간 모델을 사용해 보시겠습니까? DB 스키마와 다른 것은 동일하게 유지되지만이 모델 만 'fetch_related'할 수 있고 레이블의 ID를 가져올 수 있습니다. M2M에'through' 인수를 연결하면'add()'와 같은 일부 메소드가 깨지지만 수동으로'db_table'을 제공 할 수 있고 m2m 필드를 건드리지 않아도됩니다. – ilvar
감사합니다 @ilvar, 귀하의 의견은 아래의 답변을 이끌었다. – cberzan