Создание неограниченной иерархии форумов в Джанго - PullRequest
1 голос
/ 14 июля 2010

Я пытаюсь создать модель для форума, который хочу создать в Django.

Пока у меня есть:

class Forum(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(max_length=150)
    description = models.TextField()

    def __unicode__(self):
        return self.name

class SubForum(models.Model):
    parent_forum = models.ForeignKey('Forum', related_name='forums')
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=150)
    description = models.TextField()

    def __unicode__(self):
        if self.parent:
            return u'%s: %s - %s' % (self.parent_forum.name,
                                     self.parent.name,
                                     self.name)
        return u'%s: %s' % (self.parent_forum.name, self.name)

Это работает длябольшая часть, поскольку я могу выбрать родительскую категорию, хотя я не уверен, как выбрать родителя родительского ребенка.Например, если бы у меня было следующее:

Grandparent -> Parent -> Child

Как бы я выбрал Grandparent from Child?

Этот тип иерархии также делает администратора Django довольно беспорядочным, поскольку он не каскадноупорядоченная мода.Нужно ли создавать администратора целиком, чтобы организовать его в удобный интерфейс?

Наконец, функция __unicode__ в модели SubForum позволяет мне печатать родительский элемент, но как насчет бабушки и дедушки.Могу ли я заставить __unicode__ напечатать всех предков?

Спасибо.

Ответы [ 2 ]

6 голосов
/ 14 июля 2010

Использование родительских / дочерних отношений

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

Если вам нужно всего лишь поиск в ширину (BFS) , то есть выберите только ближайшие родители или дети одного форума, код, подобный вамнаписал, и Django ORM будет великолепен.

Вы даже можете получить прародителя ребенка, но для этого потребуется много операций SQL SELECT и JOIN, как только ORM попадет в базу данных, что потенциально можетбыть довольно медленным

Использование одной модели

Так что, хотя ваша модель в порядке, она не очень подходит для ваших требований или, более конкретно, выбрав nodes далеко вверх / вниз по иерархии, начиная со случайного узла (бабушка и дедушка ребенка).

То, что вы хотите сделать, - это построить простую N-арную структуру данных дерева, или, другими словами, иерархию и пройти по ней .Для этого вам не нужны две модели, достаточно только одной модели, имеющей отношение к себе (например, я назвал ее Node).Чтобы получить N-го родителя в этой модели, вы просто должны зацикливаться n раз каждый раз после ваших отношений (это в основном связанный список )

n = 2 # Grandparent
node = Model.objects.get(pk=1)
while n: 
   if node.parent:
      node = node.parent
# At the end of the loop `node` points to the grandparent

Моделирование древовидной структуры в SQLбаза данных

Потенциально существует множество способов реализовать деревья в базе данных SQL, но в вашем случае я бы предложил использовать MPTT , вместо, скажем, списка смежностей модель для построенияЭто.Оба являются методами для легкого манипулирования и хранения таких структур. MPTT потребуется больше записей в базу данных, чтобы добавить / переместить узлы вокруг дерева, но выбрать частичное дерево со случайным корнем (дочерним) очень просто, так как вам нужно фильтровать только по двум целочисленным полям.

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

Что касаетсяреализация MPTT в качестве приложения Django try django-mptt .

Разное: хорошая статья база данных иерархических данных дизайн.

0 голосов
/ 14 июля 2010

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

heirarchy = ""
f = this forum model
while f.parent is not null:
   heirarchy.append(f.parent.name)
   f = f.parent

, чтобы ответить на другую часть вашего вопроса, чтобы выбрать ребенка, зная идентификатор родителя, вызапросил бы объектную структуру Django следующим образом:

Forum.objects.filter(parent=PARENT_ID)

и чтобы получить прародителя ребенка, вы бы сделали:

forum_object.parent.parent
...