Родительская / дочерняя (ren) иерархия / вложенные наборы в Python / Django

Я использую Django / Python, но псевдокод здесь определенно приемлем.

Работая с некоторыми уже существующими моделями, у меня есть Employee, каждая из которых имеет Supervisor, что по сути является отношением типа внешнего ключа к другому Employee.

Где иерархия Сотрудник / Супервизор выглядит примерно так:

У любого сотрудника есть ОДИН руководитель. У этого Супервайзера может быть один или несколько Сотрудников «внизу», а также есть свой Супервайзер. Получение моего «вышестоящего» должно возвращать моего руководителя, его руководителя, ее руководителя и т. Д. До тех пор, пока я не достигну сотрудника, у которого нет руководителя.

Не зацикливаясь и не устанавливая новые приложения для управления этими отношениями, поскольку это уже существующая кодовая база и проект, я задаюсь вопросом о «питоническом» или правильном способе реализации следующих функций:

def get_upline(employee): 
    # Get a flat list of Employee objects that are
    # 'supervisors' to eachother, starting with 
    # the given Employee. 
    pass


def get_downline(employee):
    # Starting with the given Employee, find and 
    # return a flat list of all other Employees 
    # that are "below". 
    pass

Я чувствую, что может быть несколько более простой способ сделать это с помощью Django ORM, но если нет, я приму любые предложения.

Я не изучал полностью Django-MPTT, но если я смогу оставить модели в неизменном виде и просто получить больше функциональности, это того стоит.


person anonymous coward    schedule 29.06.2010    source источник


Ответы (2)


Вам не нужно прикасаться к своим моделям, чтобы использовать django-mptt; вам просто нужно создать поле parent в вашей модели, django-mptt создает все остальные атрибуты для mptt автоматически, когда вы регистрируете свою модель: mptt.register(MyModel).

Хотя, если вам просто нужна иерархия «вышестоящих», вам не понадобятся вложенные наборы. Более серьезная проблема с производительностью идет в противоположном направлении и собирает, например. children / leaves и т. д., что делает необходимым работу с моделью вложенных множеств!

person Bernhard Vallant    schedule 29.06.2010
comment
На самом деле список вышестоящих / родителей намного важнее, чем дети. Каков простой подход к этому? Было бы быстрее читать документы / реализовывать djang-mptt? - person anonymous coward; 29.06.2010
comment
На самом деле вам нужно четыре новых поля для mptt: parent, level, left и right. - person Daniel Roseman; 29.06.2010

Реляционные базы данных не подходят для такого рода запросов к графам, поэтому единственный вариант - выполнить несколько запросов. Вот рекурсивная реализация:

def get_upline(employee):
    if self.supervisor:
        return [employee] + self.supervisor.get_upline()
    else:
        return [employee]

def get_download(employee):
    l = [employee]
    for minion in self.minion_set.all():
        l.extend(minion.get_download())
    return l
person Vebjorn Ljosa    schedule 29.06.2010
comment
Нужно ли мне добавить сюда чек на пустой supervisor в get_upline()? Я представляю себе исключение или что-то, что происходит при достижении корня. Я ошибся? - person anonymous coward; 29.06.2010
comment
Вебьорн, не могли бы вы объяснить, откуда взялся self.minion_set.all()? - person Tommy Gibbons; 17.08.2015
comment
@TommyGibbons, это RelatedManager для отношения с именем minion. - person Vebjorn Ljosa; 17.08.2015
comment
@Vebjorn Ljosa. Под отношением правильно ли я понимаю класс в models.py или таблицу в БД? Если это так, справедливо будет сказать, что FK в minion указывает на PK в employee. Отсюда dir (employee) вернет minion_set как один параметр. Я просто пытаюсь прояснить эту структуру в своей голове. - person Tommy Gibbons; 17.08.2015
comment
@TommyGibbons: Правильно (если я вас правильно понял). - person Vebjorn Ljosa; 18.08.2015
comment
@Vebjorn Ljosa: У меня class EmployeeDynamic, FK для сотрудника, FK для пользователя (пользователь-администратор Django). Использование dir (EmployeeDynamic) не возвращает user_set. Я пытаюсь перечислить всех сотрудников в цепочке Супервайзер - Супервайзер - Сотрудник. - person Tommy Gibbons; 18.08.2015
comment
@TommyGibbons: …_set вы увидите только на многих сторонах отношений «многие к одному». Если внешний ключ для пользователя находится в EmployeeDynamic (так что у вас есть столбец user_id в таблице app_employeedynamic в базе данных), то сторона многих - это сторона пользователя. Вам, вероятно, следует нарисовать диаграмму E-R и убедиться, что вы понимаете, что такое база данных, прежде чем добавлять сбивающие с толку биты Django. - person Vebjorn Ljosa; 18.08.2015
comment
смешивание запутанных битов Django. Ага, понял. Спасибо. - person Tommy Gibbons; 18.08.2015