2011-04-13 80 views
2

創建高效的數據庫查詢考慮這個(Django的)模型:分層模型(Django的)

class Source(models.Model): 
    # Some other fields 
    type = models.ForeignKey('Type') 

class Type(models.Model): 
    # Some other fields 
    parent = models.ForeignKey('self') 

這種模式有一個外鍵本身,從而創造一個層次。

比方說,我們有以下層次:

Website 
    Blog 
    News  
    Social Network 
    Q&A 
    Forum 
Radio 
    Government radio 
    Pirate radio 
    Commercial radio 
    Internet radio 

如何有效地查詢,這樣,如果我通過Type選擇Source,我也找回Sources其中有一個Type是給定類型的子?

我嘗試遍歷整個樹,但這並不十分有效。

另一種選擇是使用ManyToManyField並通過覆蓋save()方法自動附加父類型。例如,如果選擇「博客」,則還會創建「網站」的記錄。但這對我來說似乎有點矯枉過正。

回答

5

django-mptt或django-treebeard是分層數據的好幫手。它們都向模型添加額外的元數據以允許有效的查詢。

如果您選擇使用Django的樹胡模型可能是這個樣子:

from django.db import models 
from treebeard.mp_tree import MP_Node 

class Source(models.Model): 
    # Some other fields 
    type = models.ForeignKey('Type') 

class Type(MP_Node): 
    # Some other fields 
    name = models.CharField(max_length=100) 

    # parent gets added automatically by treebeard 
    # parent = models.ForeignKey('self', blank=True, null=True) 

,並可以查詢這樣的:

# get all Sources of Type type and descendants of type 
type = Type.objects.get(name='Radio') 
Source.objects.filter(type__in=type.get_descendants()) 

看到https://tabo.pe/projects/django-treebeard/docs/tip/api.html更多可能的查詢

1

這樣的結構可以很容易地使用遞歸公用表表達式來檢索。

一個例子是例如在這裏:http://www.postgresql.org/docs/current/static/queries-with.html

+0

雖然這個例子與Django並不相關。 – 2015-12-07 16:40:20

+0

@Centralniak:爲什麼?你不能用這個Django的東西來運行SQL查詢嗎? – 2015-12-07 17:33:49

1

如何有效地查詢,以便如果 我選擇源按類型,我也 檢索的有型 是給定類型的子來源?

對於給出的例子,它是很容易設置一個查詢,因爲沒有遞歸調用需要做,而你的「層次」是隻有一層深:

class Source(models.Model): 
    # Some other fields 
    type = models.ForeignKey('Type') 

class Type(models.Model): 
    # Some other fields 
    name = models.CharField(max_length=100) 
    parent = models.ForeignKey('self', blank=True, null=True) 

#We want all sources under in the type = Radio tree 
type = Type.objects.get(name='Radio') 
qs = Source.objects.filter(type__parent=type) 

#We want all sources that are `Forum` typed 
type = Type.objects.get(name='Forum') 
qs = Source.objects.filter(type=type) 

這是假設來源始終與「孩子」類型相關,而不與「父母」相關。

如果源也可與「父」的類型,你可以用Q複雜查詢:

>>> from django.db.models import Q 
>>> type = Type.objects.get(name='Radio') 
>>> qs = Source.objects.filter(Q(type=type)|Q(type_parent=type)) 
>>> #if Radio type id = 2 
>>> print qs.query 
SELECT `app_source`.`id`, `app_source`.`type_id` FROM `app_source` INNER JOIN `app_type` ON (`app_source`.`type_id` = `app_type`.`id`) WHERE (`app_source`.`type_id` = 2 OR `app_type`.`parent_id` = 2) 
>>> 

如果你對你的表真正的分層樹,這種方法更實用,你應該尋找另一種解決方案。