Skip to content
Advertisement

Model hierarchy in Django [closed]

Sorry for the long text

Models are given:

  1. User

  2. Hierarchy

    class Hierarchy (Model):

      owner = OneToOneField(User)
      subordinates = ManyToManyField(User)
    

There are users, they can invite each other. The invitees, in turn, can accept the invite or reject it.

Suppose that Mark invited Masha, Katya and Dima. Masha accepted Mark’s invitation, and even invited Kolya herself.

On one tab, you need to display the hierarchy.

Continuing the example, Mark should have:

1st level: Masha, Katya, Dima
2nd level: Kolya and other guys

1st level for Mark - those whom he invited.
2nd level - those who were invited by people invited by Mark.

And so on.

Tell me how to implement it | what to familiarize yourself with to get closer to the result

Advertisement

Answer

As far as I understand, you want a tree, not a graph. In such cases To minimize database queries you need to modernize your hierarchy model

from django.db import models
from django.conf import settings
from mptt.models import MPTTModel, TreeForeignKey

class Hierarchy(MPTTModel):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    owner = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='subordinates')

    class MPTTMeta:
        parent_attr = 'owner'
        level_attr = 'mptt_level'
        order_insertion_by=['user']

  • Get your list
from django.shortcuts import get_object_or_404
from .models import Hierarchy
# Get owner
owner = get_object_or_404(Hierarchy, pk=owner_id)
# Get tree users from database
users = Hierarchy.objects.filter(tree_id=owner.tree_id, level__gt=owner.level).select_related('user').order_by('level')

# serialize tree
users_list = []           # list levels users  with users   
users_on_level = []       # list of users of the current tree level
tree_level = owner.level  # current tree level

for user in users:
    if user.level > tree_level:
        tree_level += 1
        users_list.append(users_on_level)
        users_on_level = []
    users_on_level.append(user)

# output users
for level, users in enumerate(users_list, 1):
    print(f"{level} - {', '.join(str(user.username) for user in users) }"

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement