Создание эффективных запросов к базе данных для иерархических моделей (django) - PullRequest
3 голосов
/ 13 апреля 2011

Рассмотрим эту (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, который является потомком данного типа?

Я пробовал обходить все дерево, но это, очевидно, не очень эффективно.

Другой вариант - использовать ManyToManyField и автоматически присоединять родительские типы, переопределяя save ().метод.Например, если выбран «блог», также создается запись для «веб-сайта».Но это кажется мне излишним.

Ответы [ 3 ]

5 голосов
/ 14 апреля 2011

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 голос
/ 14 апреля 2011

Как эффективно выполнить запрос, чтобы при выборе источника по типу я также получал источники, которые имеют тип, являющийся дочерним по отношению к данному типу?

для приведенного примерадовольно просто настроить запрос, потому что не нужно выполнять рекурсивные вызовы, а ваша «иерархия» имеет глубину только одного уровня:

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»"тип, а не" родителю ".

Если источники также могут быть связаны с «родительскими» типами, вы можете использовать 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 )
>>> 

Если в ваших таблицах действительно иерархические деревья, этот методгораздо менее полезный, и вы должны искать другое решение.

1 голос
/ 13 апреля 2011

Такая структура может быть легко получена с помощью рекурсивного общего табличного выражения.

Примером является, например, здесь: http://www.postgresql.org/docs/current/static/queries-with.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...