2011-04-13 53 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) 
>>> 

如果你对你的表真正的分层树,这种方法更实用,你应该寻找另一种解决方案。