Thursday, 1 July 2021

How to implement Django multiple user types, while one user can have different role according to the project he/she is working on?

I couldn't find a solution to my problem and would appreciate comments/help on this.

I would like to develop a multiple user type model in Django, along the lines of this video where the author is using Django Proxy Models.

Situation

I have a list of XX projects (proj01, proj02 , projXX, ...). All these projects have their specific page that can be accessed through a specific url mysite/projXX/

I have multiple users: Adam, Bob, Caroline, Dany, Ed, ...

Each user can have several roles according to the project they are working on (e.g. manager, developer, documentarist, reviewer, editor, ...)

A user can have a different role according to the project. E.g. Adam can be reviewer on proj01 but editor on proj02 while Bob can be editor on proj01 but reviewer on proj02, etc..

I started defining multiple user types in the models.py file below (only reviewer and editor roles):

# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _


class User(AbstractUser):
    class Types(models.TextChoices):
        EDITOR= "EDITOR", "Editor"
        REVIEWER = "REVIEWER", "Reviewer"

    base_type = Types.EDITOR

    type = models.CharField(
        _("Type"), max_length=50, choices=Types.choices, default=base_type
    )

    name = models.CharField(_("Name of User"), blank=True, max_length=255)

    def get_absolute_url(self):
        return reverse("users:detail", kwargs={"username": self.username})

    def save(self, *args, **kwargs):
        if not self.id:
            self.type = self.base_type
        return super().save(*args, **kwargs)


class EditorManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(type=User.Types.EDITOR)


class ReviewerManager(models.Manager):
    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(type=User.Types.REVIEWER)


class EditorMore(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    gadgets = models.TextField()


class Editor(User):
    base_type = User.Types.EDITOR
    objects = EditorManager()

    class Meta:
        proxy = True

    def edit(self):
        return "Edition in progress"


class ReviewerMore(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    model = models.CharField(max_length=255)
    make = models.CharField(max_length=255)
    year = models.IntegerField()


class Reviewer(User):
    base_type = User.Types.REVIEWER
    objects = ReviewerManager()

    @property
    def more(self):
        return self.reviewermore

    class Meta:
        proxy = True

    def review(self):
        return "In Review" 

Question:

What is the best way to handle the fact that the role of the user can change according to the project page he/she is visiting?

Example: If Adam is logged in and visits the page mysite/proj01/ I would like him to access only the content allowed for a reviewer while if Adam visit mysite/proj02/, I would like the user to see only the content allowed to the editor.

Ideally, I would like each user to have its unique entry in the user database. I was thinking that the project-dependent role level could be stored as a dictionary? For example:

{'proj01':'reviewer', 'proj02':'editor', 'projxx': 'roleY', ... } 

How would you implement that assuming you created an accounts app for user management?



from How to implement Django multiple user types, while one user can have different role according to the project he/she is working on?

No comments:

Post a Comment