I'm using Python and Django. How can I create a web page that displays the employee hierarchy in a tree-like structure?
For example:
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)
Currently, my code looks like this:
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')
How can views.py and the employee_hierarchy.html template look like? And where is the best place to implement the logic: in the model, view, or template? Thank you in advance!
I tried the following code in 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 %}
I obtained the following result:
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
I'm a beginner in programming. Please advise me on how to best implement the employee hierarchy in a tree-like structure.
too long for comment
Within your current approach it can be accomplished by changing .all() in the view to filter(manager__isnull=true). This will select top-level employees only and your nested template inclusion will do the rest. Also I'd suggest to add predictable sort order for both top level employees and subordinates. Otherwise each page refresh will render different tree.
But this recursive walking through subordinates will end up in a terrible performance: each recursive call will run a separate query. The solution is to build the tree before rendering. This can be accomplished with a recursive employee processing in the view or with storing all the hierarchy data in DB.
The second would need a hierarchy_id string column where you'd have to store full path to the node in the tree, e.g. /1/2/3/ for employee_id=3 who is a subordinate of employee_id=2 who is a subordinate of employee_id=1. And level int column would be helpful. These columns should be filled during save.
Thus you'd have a ready to use tree which can be rendered with a single for loop just sorted by hyerarchy_id. And locating subordinate subtree would be trivial: hyerarchy_id__startswith=self.hyerarchy_id. But this approach is a little harder to implement. And you should be careful with tree alterations. If you move an employee from one position to another in the middle of tree, you'd need to update hyerarchy_id of all the old subordinates and new ones.
One more approach is to build tree by JS on template side. View just passes all the employees you have and JS runs recursive things on client side.
Implementing efficient tree/graph structures in DB and UI is not a trivial task thus using something third-party is not a bad idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With