danielmoessner
danielmoessner

Reputation: 379

How to set up django user permissions with one user having multiple permissions?

I've got the following idea. One user can be in multiple companies. The user has different permissions in every company that he or she is in. The example below doesn't work, because one user would always have the same permissions.

How should I set up my User Model that one User has a different permission in every company?

That's what I've tried so far:

class User(AbstractUser):
    hourly_wage = models.DecimalField(decimal_places=2, max_digits=6, default=8.50)

    class Meta:
        permissions = (("is_general", "Can add people to his company and see everything"),
                       ("is_captain", "Can add/edit/delete everything"),
                       ("is_staff", "Can add/edit/delete jobs"),
                       ("is_programmer", "Can do what he or she wants to do"))

    def clean(self):
        self.username = self.username.lower()


class Company(models.Model):
    name = models.CharField(max_length=80)
    slug = models.SlugField(unique=True)
    users = models.ManyToManyField(User, related_name="companies")

    class Meta:
        verbose_name_plural = "companies"

Upvotes: 2

Views: 2093

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476604

You define a model for the ManyToManyField through which the many to many relation flows.

So instead of:

+---------+ M      N +-------------+ M      N +------------+
| Company |----------| User        |----------| Permission |
+---------+          +-------------+          +------------+
                     | permissions |
                     +-------------+

We thus write it like:

+---------+ 1      N +-------------+ M      1 +------+
| Company |----------| UserCompany |----------| User |
+---------+          +-------------+          +------+
                            | M
                            |
                            | N
                     +------------+
                     | Permission |
                     +------------+

We can do this with:

from django.contrib.auth.models import Permission

class User(AbstractUser):

    def clean(self):
        self.username = self.username.lower()


class Company(models.Model):
    name = models.CharField(max_length=80)
    slug = models.SlugField(unique=True)
    users = models.ManyToManyField(User, through='app.CompanyUser', related_name="companies")

    class Meta:
        verbose_name_plural = "companies"


class CompanyUser(models.Model):

    user = models.ForeignKey('app.User', on_delete=models.CASCADE)
    company = models.ForeignKey('app.Company', on_delete=models.CASCADE)
    hourly_wage = models.DecimalField(decimal_places=2, max_digits=6, default=8.50)
    permissions = models.ManyToManyField(Permission, on_delete=models.CASCADE)

You probably want to shift other logic to the through model. For example thehourly_wage is probably also related to a (User, Company)-pair, and not specific to a User itself.

You can thus add permissions to the UserCompany with:

someusercompany.permissions.add(some_permission)

Then you check if a UserCompany has a permission with:

CompanyUser.objects.filter(
    user=some_user,
    company=some_company,
    some_permission=some_permission
).exists()

See more about this in the documentation about through parameter [django-doc].

Upvotes: 2

Related Questions