-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨(teams) add Team dependencies #560
base: main
Are you sure you want to change the base?
Changes from all commits
d0c5d71
61643ee
d68645e
38df22d
26b1880
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Generated by Django 5.1.3 on 2024-11-26 13:55 | ||
|
||
from django.db import migrations, models | ||
|
||
from treebeard.numconv import NumConv | ||
|
||
|
||
def update_team_paths(apps, schema_editor): | ||
Team = apps.get_model("core", "Team") | ||
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||
steplen = 5 | ||
|
||
# Initialize NumConv with the specified custom alphabet | ||
converter = NumConv(len(alphabet), alphabet) | ||
|
||
nodes = Team.objects.all().order_by("created_at") | ||
for i, node in enumerate(nodes, 1): | ||
node.depth = 1 # root nodes are at depth 1 | ||
|
||
# Use NumConv to encode the index `i` to a base representation and | ||
# pad it to the specified step length using the custom alphabet | ||
node.path = converter.int2str(i).rjust(steplen, alphabet[0]) | ||
|
||
if nodes: | ||
Team.objects.bulk_update(nodes, ["depth", "path"]) | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('core', '0009_contacts_add_index_on_data_emails'), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name='team', | ||
name='depth', | ||
field=models.PositiveIntegerField(default=0), | ||
preserve_default=False, | ||
), | ||
migrations.AddField( | ||
model_name='team', | ||
name='numchild', | ||
field=models.PositiveIntegerField(default=0), | ||
), | ||
migrations.AddField( | ||
model_name='team', | ||
name='path', | ||
field=models.CharField(default='', max_length=400, db_collation="C"), | ||
preserve_default=False, | ||
), | ||
migrations.RunPython(update_team_paths, migrations.RunPython.noop), | ||
migrations.AlterField( | ||
model_name="team", | ||
name="path", | ||
field=models.CharField(unique=True, max_length=400, db_collation="C"), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
|
||
import jsonschema | ||
from timezone_field import TimeZoneField | ||
from treebeard.mp_tree import MP_Node, MP_NodeManager | ||
|
||
from core.enums import WebhookStatusChoices | ||
from core.plugins.loader import organization_plugins_run_after_create | ||
|
@@ -633,7 +634,34 @@ def __str__(self): | |
return f"{self.user!s} is {self.role:s} in organization {self.organization!s}" | ||
|
||
|
||
class Team(BaseModel): | ||
class TeamManager(MP_NodeManager): | ||
""" | ||
Custom manager for the Team model, to manage complexity/automation. | ||
""" | ||
|
||
def create(self, parent_id=None, **kwargs): | ||
""" | ||
Replace the default create method to ease the Team creation process. | ||
|
||
Notes: | ||
- the `add_*` methods from django-treebeard does not support the "using db". | ||
Which means it will always use the default db. | ||
- the `add_*` methods from django-treebeard does not support the "force_insert". | ||
|
||
""" | ||
if parent_id is None: | ||
return self.model.add_root(**kwargs) | ||
|
||
# Retrieve parent object, because django-treebeard uses raw queries for most | ||
# write operations, and raw queries don’t update the django objects of the db | ||
# entries they modify. See caveats in the django-treebeard documentation. | ||
# This might be changed later if we never do any operation on the parent object | ||
# before creating the child. | ||
# Beware the N+1 here. | ||
return self.get(pk=parent_id).add_child(**kwargs) | ||
|
||
|
||
class Team(MP_Node, BaseModel): | ||
""" | ||
Represents the link between teams and users, specifying the role a user has in a team. | ||
|
||
|
@@ -643,6 +671,12 @@ class Team(BaseModel): | |
Team `service_providers`. | ||
""" | ||
|
||
# Allow up to 80 nested teams with 62^5 (916_132_832) root nodes | ||
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||
# Django treebeard does not allow max_length = None... | ||
steplen = 5 | ||
path = models.CharField(max_length=5 * 80, unique=True, db_collation="C") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was wondering if this collation impacts the use of "startswith" 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
So I guess it's only better :) Actually it still works properly in the specific case of "startswith" but I can't tell for the performance improvement or not. |
||
|
||
name = models.CharField(max_length=100) | ||
|
||
users = models.ManyToManyField( | ||
|
@@ -664,6 +698,8 @@ class Team(BaseModel): | |
blank=True, | ||
) | ||
|
||
objects = TeamManager() | ||
|
||
class Meta: | ||
db_table = "people_team" | ||
ordering = ("name",) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not expect the parent object directly? It seems to me what we expect when playing with objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't use the object directly to be safer (even if sub-optimized) because as stated in django-treebeard documentation, it's important to have nodes up to date when doing such operations.
Do you think I should update the comment?