我試圖優化Django應用程序的數據庫查詢。下面是一個簡化的例子:django多對多字段:僅預取主鍵
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
S和Thing
秒和將其放入一個JSON數據結構,其中Thing
S使用其id
S(主密鑰)是指Label
秒的功能。事情是這樣的:
{
'labels': [
{ 'id': 123, 'name': 'label foo' },
...
],
'things': [
{ 'id': 45, 'name': 'thing bar', 'labels': [ 123, ... ] },
...
]
}
什麼是獲得使用Django這樣的數據結構的最有效的方法是什麼?假設我有大號Label
S和牛逼Thing
秒,平均Thing
具有XLabel
秒。
方法1:
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 + Ť)數據庫查詢,因爲model_to_dict(thing)
需要爲每個單獨Thing
取Label
秒。
方法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
S IN單個附加查詢預取。
這仍然不令人滿意。prefetch_related('labels')
將獲取相同的Label
許多副本,而我只需要他們的id
s。是否有任何方法只能預取Label
的id
?我試過prefetch_related('labels__id')
,但沒有奏效。我還擔心,因爲T很大(數百),所以prefetch_related('labels')
會導致帶有大型IN
子句的SQL查詢。 大號小得多(< 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
s,如果Thing
有多個Label
s。
總結:
Label
和Thing
由ManyToManyField
連接。無論如何,我取全部Label
s和Thing
。那麼我怎樣纔能有效地獲取他們的多對多關係呢?
也許嘗試使用m2m的中介模型?數據庫方案和其他任何東西都會保持不變,但是您只能從這個模型中獲取「相關」,並從中獲取標籤的ID。如果你將它與M2M的'through'參數聯繫起來,一些像add()這樣的方法將會被破壞,但你可以手動爲它提供'db_table'並且不要觸摸m2m字段,所以它應該可以工作。 – ilvar 2012-04-23 04:26:05
感謝@ilvar,您的評論讓我回到了下面的答案。 – cberzan 2012-04-24 02:09:32