bennylope / django-organizations

:couple: Multi-user accounts for Django projects
http://django-organizations.readthedocs.org/
BSD 2-Clause "Simplified" License
1.31k stars 212 forks source link

Multiple Organizations #187

Closed steverecio closed 4 years ago

steverecio commented 4 years ago

I read the documentation on using multiple organizations but I'm getting an error introducing the second organization. How do I link users to the second organization? I want the ability to create a team and then additionally create user groups underneath that structure. The rationale is an organization invites their employees to the platform and then can organize them into groups who can share information.

When running the migration to add the Group model I get the following error: teams.TeamMember: (fields.E336) The model is used as an intermediate model by 'teams.Group.users', but it does not have a foreign key to 'Group' or 'User'.

See models below:

from functools import partial
from django.db import models
from organizations.utils import create_organization
from organizations.abstract import (AbstractOrganization,
                                    AbstractOrganizationUser,
                                    AbstractOrganizationOwner)

class Team(AbstractOrganization):
    """
    Root model for team structure
    """
    @classmethod
    def create_team(cls, *args, **kwargs):
        func = partial(create_organization, model=cls)
        return func(*args, **kwargs)

    @property
    def team_members(self):
        return self.organization_users

class TeamMember(AbstractOrganizationUser):
    """
    An individual on a team
    """
    @property
    def team(self):
        return self.organization

class TeamAdmin(AbstractOrganizationOwner):
    """
    The administrator for a team
    """
    @property
    def team(self):
        return self.organization

    @property
    def team_member(self):
        return self.organization_user

class Group(AbstractOrganization):
    """
    Root model for user groups
    """

    team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='team')

    @classmethod
    def create_group(cls, *args, **kwargs):
        func = partial(create_organization, model=cls)
        return func(*args, **kwargs)

    @property
    def group_members(self):
        return self.organization_users
bennylope commented 4 years ago

Are these all in the same app?

steverecio commented 4 years ago

Yeah I have a SaaS platform built on django and these models are all in a django app called teams. Is there a reason I would need to separate the parent orgs and user groups into separate django apps?

bennylope commented 4 years ago

Yep, it's a limitation of how the abstract metaclasses work.

Unlike in the example of multi-table inheritance, you cannot add more than one custom organization model to an individual app. Each additional organization class you want must be defined in its own app. Only one organization set per app. (from a note buried in the docs).

You have a couple of options:

  1. Create a separate app for the sub groups (for the Group functionality)
  2. Create the Group related models using a different strategy than the AbstractOrganization class

I'd give consideration to the first option regardless of how you approach this, for the reasons above and for general architectural concerns. If you're not interested in using other features like view mixins and invitations for the Groups, you could use a simple model with a ForeignKey to your main Team model and a ManyToMany field linking to your TeamMember model.

steverecio commented 4 years ago

Ok yeah I missed that note about one org per app. I built my own invitations app because it didn't work very easily with my SPA / DRF setup. I'll have to think about the pros / cons of the two approaches. I think I only really need a simple ManyToMany field but it may still make sense to split out user groups into its own app from an organizational perspective.