考虑这个(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
如何有效地进行查询,以便在Source
之后选择Type
时,我还会检索Sources
Type
,其中{{1}}是给定类型?
我试过遍历整棵树,但这显然不是很有效。
另一种选择是使用ManyToManyField并通过覆盖save()方法自动附加父类型。例如,如果选择“博客”,则还会创建“网站”的记录。但这对我来说似乎有点过分了。
答案 0 :(得分:5)
django-mptt或django-treebeard是分层数据的好帮手。它们都为模型添加了额外的元数据,以便进行有效的查询。
如果您选择使用django-treebeard,您的模型可能如下所示:
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 :(得分:1)
使用递归公用表表达式可以轻松检索到这样的结构。
一个例子是例如在这里:http://www.postgresql.org/docs/current/static/queries-with.html
答案 2 :(得分:1)
如何高效查询以便if 我选择Source by Type,我也是 检索具有类型的源 那是给定类型的孩子?
对于给出的示例,设置查询相当容易,因为不需要进行递归调用,并且您的“层次结构”只有一层深度:
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)
这假设Source始终与“child”类型相关,而不是与“parent”相关。
如果源也可以与“父”类型相关,则可以将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 )
>>>
如果表中有一个真正的分层树,这种方法的可用性要小得多,你应该找到另一个解决方案。