Python,Django。以树状结构的层次关系。

3

我正在使用Python和Django。如何创建一个以树状结构显示员工层级关系的网页?

例如:

Employee-1 (Manager -)
    Employee-2 (Manager:Employee-1)
        Employee-3 (Manager :Employee-2)
            Employee-4 (Manager:Employee-3)
    Employee-5 (Manager :Employee-1)
        Employee-6 (Manager:Employee-5)
            Employee-7 (Manager :Employee-6)
        Employee-8 (Manager:Employee-5)

目前,我的代码看起来是这样的:

models.py:

class Employee(models.Model):
    name = models.CharField(max_length=100)
    position = models.CharField(max_length=100)
    hire_date = models.DateField()
    salary = models.DecimalField(max_digits=8, decimal_places=2)
    manager = models.ForeignKey('self', on_delete=models.CASCADE, related_name='subordinates')

views.py和employee_hierarchy.html模板应该是什么样子的?在哪里实现逻辑最好:模型、视图还是模板?提前感谢!
我在views.py中尝试了以下代码:
def employee_hierarchy(request):
    employees = Employee.objects.select_related('manager').all()
    return render(request, 'employees/employee_hierarchy.html', {'employees': employees})

employee_hierarchy.html:

<body>
   <h1>Employee Hierarchy</h1>
   <ul>
       {% for employee in employees %}
           {% include 'employees/employee_item.html' with employee=employee %}
       {% endfor %}
   </ul>
</body>

employee_item.html:

<li>{{ employee.name }} ({{ employee.position }}) - Manager: {% if employee.manager %}{{ employee.manager.name }}{% endif %}</li>
{% if employee.subordinates.all %}
   <ol>
       {% for subordinate in employee.subordinates.all %}
           {% include 'employees/employee_item.html' with employee=subordinate %}
       {% endfor %}
   </ol>
{% endif %}

我得到了以下的结果:
 Employee-2 - Manager: Employee-1
     Employee-3 - Manager: Employee-2
 Employee-3 - Manager: Employee-2
 Employee-4 - Manager: Employee-1
     Employee-5 - Manager: Employee-4
         Employee-6 - Manager: Employee-5
 Employee-5 - Manager: Employee-4
     Employee-6 - Manager: Employee-5
 Employee-6 - Manager: Employee-5

我是一个编程初学者。请给我一些建议,告诉我如何最好地在类似树形结构中实现员工层级关系。

2
对于一个“初学者”来说,你已经做得非常出色了! - Sebastian Wozny
2
对于一个“初学者”来说,你已经做得非常出色了! - Sebastian Wozny
1个回答

1

太长了,无法在评论中回答

根据您目前的方法,可以通过将视图中的.all()更改为filter(manager__isnull=true)来实现。这将仅选择顶级员工,而嵌套模板包含将完成其余部分。另外,我建议为顶级员工和subordinates添加可预测的排序顺序。否则,每次刷新页面都会呈现不同的树形结构。

但是,通过对subordinates进行递归遍历将导致性能非常差:每个递归调用都会运行一个单独的查询。解决方案是在渲染之前构建树形结构。可以通过在视图中进行递归员工处理或在数据库中存储所有层级数据来实现。

后者需要一个hierarchy_id字符串列,您需要在其中存储树中节点的完整路径,例如/1/2/3/表示employee_id=3employee_id=2的下属,而employee_id=2employee_id=1的下属。还有一个有用的level整数列。这些列应在save期间填充。

因此,你将拥有一个“准备好使用的树”,可以通过单个“for”循环按照层次结构ID排序进行渲染。定位下级子树将变得简单:`hyerarchy_id__startswith=self.hyerarchy_id`。但是,这种方法稍微难以实现。在对树进行更改时需要小心。如果你将一个员工从树的中间位置移动到另一个位置,你需要更新所有旧下属和新下属的层次结构ID。
另一种方法是在模板端使用JS构建树。视图只传递你拥有的所有员工,JS在客户端上运行递归操作。
在数据库和用户界面中实现高效的树/图结构并不是一项简单的任务,因此使用第三方工具并不是一个坏主意。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接